一种在 Scala 中避免 asInstanceOf 的方法
A way to avoid asInstanceOf 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))
我无法更改类型层次结构或列表类型。
是否有更好的方法来避免 asInstanceOf[B[_]] 语句?
您可以尝试模式匹配。
l.collect{case x :B[_] => println(x.v)}
您可以尝试这样的操作:
for (x <- l.view; y <- Some(x).collect { case b: B[_] => b }) println(y.v)
它不需要任何 isInstanceOf
或 asInstanceOf
,并且永远不会崩溃,即使您的列表包含 A
而不是 B[_]
。它也不会创建任何冗长的列表作为中间结果,只会创建短暂的 Option
s.
不是那么简洁,但也不那么令人惊讶的解决方案:
for (x <- l) {
x match {
case b: B[_] => println(b.v)
case _ => /* do nothing */
}
}
如果您可以将 l
的类型更改为 List[B[_]]
,这将是更好的解决方案。
我认为最理想的方法是为 B
提供提取器对象和 B
值的模式匹配:
object B {
def unapply[T](arg: B[T]): Some[T] = Some(arg.v)
}
l.collect{case B(x) => println(x)}
如果在源文件中声明了 B
您无法更改,您可能需要为提取器对象使用不同的名称。
我在 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))
我无法更改类型层次结构或列表类型。
是否有更好的方法来避免 asInstanceOf[B[_]] 语句?
您可以尝试模式匹配。
l.collect{case x :B[_] => println(x.v)}
您可以尝试这样的操作:
for (x <- l.view; y <- Some(x).collect { case b: B[_] => b }) println(y.v)
它不需要任何 isInstanceOf
或 asInstanceOf
,并且永远不会崩溃,即使您的列表包含 A
而不是 B[_]
。它也不会创建任何冗长的列表作为中间结果,只会创建短暂的 Option
s.
不是那么简洁,但也不那么令人惊讶的解决方案:
for (x <- l) {
x match {
case b: B[_] => println(b.v)
case _ => /* do nothing */
}
}
如果您可以将 l
的类型更改为 List[B[_]]
,这将是更好的解决方案。
我认为最理想的方法是为 B
提供提取器对象和 B
值的模式匹配:
object B {
def unapply[T](arg: B[T]): Some[T] = Some(arg.v)
}
l.collect{case B(x) => println(x)}
如果在源文件中声明了 B
您无法更改,您可能需要为提取器对象使用不同的名称。