[英]A way to avoid asInstanceOf in Scala
I have this hierarchy of traits and classes in Scala: 我在Scala中具有以下特征和类层次结构:
trait A
trait B[T] extends A {
def v: T
}
case class C(v:Int) extends B[Int]
case class D(v:String) extends B[String]
val l:List[A] = C(1) :: D("a") :: Nil
l.foreach(t => println(t.asInstanceOf[B[_]].v))
I cannot change the type hierarchy or the type of the list. 我无法更改类型层次结构或列表的类型。
Is there a better way to avoid the asInstanceOf[B[_]] statement? 有更好的方法来避免asInstanceOf [B [_]]语句吗?
您可以尝试模式匹配。
l.collect{case x :B[_] => println(x.v)}
You might try something like this: 您可以尝试如下操作:
for (x <- l.view; y <- Some(x).collect { case b: B[_] => b }) println(y.v)
It doesn't require any isInstanceOf
or asInstanceOf
, and never crashes, even if your list contains A
s that aren't B[_]
s. 它不需要任何
isInstanceOf
或asInstanceOf
,并且永远不会崩溃,即使您的列表包含不是B[_]
的A
It also doesn't create any lengthy lists as intermediate results, only small short-lived Option
s. 它还不会创建任何冗长的列表作为中间结果,而只会创建短期的
Option
。
Not as concise, but also much less surprising solution: 不那么简洁,但是也没有那么令人惊讶的解决方案:
for (x <- l) {
x match {
case b: B[_] => println(b.v)
case _ => /* do nothing */
}
}
If you could change the type of l
to List[B[_]]
, this would be the preferable solution. 如果可以将
l
的类型更改为List[B[_]]
,则这将是更可取的解决方案。
I think the most ideomatic way to do it would be to supply B
with an extractor object and pattern match for B
values: 我认为最理想的方法是为
B
提供一个提取器对象,并为B
值提供模式匹配:
object B {
def unapply[T](arg: B[T]): Some[T] = Some(arg.v)
}
l.collect{case B(x) => println(x)}
If B
is declared in a source file you can't alter you might need a different name for the extractor object. 如果在源文件中声明了
B
则无法更改,您可能需要为extractor对象使用其他名称。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.