假设我有以下类层次结构:
trait A; class A1 extends A; class A2 extends A
现在我需要在List[A]
中筛选A1
实例。我使用模式匹配或isInstanceOf
。
as.filter(cond(_){case _: A1 => true}) // use pattern matching
as.filter(_.isInstanceOf[A1]) // use isInstanceOf
它也一样吗?你喜欢什么?
为什么不使用collect?这还有一个额外的好处,即返回的列表将是正确的类型(list[A1]而不是list[A])
val a1s = as.collect { case x:A1 => x }
虽然接受的答案给了你一个很好的建议,但请注意,scala中的typecase与使用isInstanceOf
和asInstanceOf
没有什么不同。这两个例子大致相当:
def foo(x: Any) = x match {
case s: String = println(s"$s is a String)
case _ => println("something else")
}
def foo(x: Any) = x match {
case _ if x.isInstanceOf[String] => println(s${x.asInstanceOf[String]} is a String)
case _ => println("something else")
}
因此,在你的具体例子中,你使用这两种方法中的哪一种并不重要:你最终总是会做某种下转换,这是通常要避免的。
看看第二个版本是如何变得相当丑陋,因此更合适,因为你在用函数式语言做一件"丑陋"的事情。
所以,我会选择
val a1s = as.collect{case x if x.isInstanceOf[A1] => x.asInstanceOf[A1]}
丑陋的东西应该看起来丑陋。
它也一样吗?
将生成相同的答案,但在每种情况下都会发出不同的代码,正如您所期望的那样。
您可以检查在每种情况下生成的IL,如下所示。创建一个包含以下内容的"test.scala
"文件:
import PartialFunction.cond
trait A; class A1 extends A; class A2 extends A
class Filterer {
def filter1(as: List[A]) =
as.filter(cond(_){case _: A1 => true}) // use pattern matching
def filter2(as: List[A]) =
as.filter(_.isInstanceOf[A1]) // use isInstanceOf
}
然后运行:
scalac test.scala
要检查as.filter(cond(_){case _: A1 => true})
版本的IL,请执行
javap -c 'Filterer$$anonfun$filter1$1'
javap -c 'Filterer$$anonfun$filter1$1$$anonfun$apply$1'
然后要检查as.filter(_.isInstanceOf[A1])
版本的IL,可以执行
javap -c 'Filterer$$anonfun$filter2$1'
"cond
"版本使用了更多的中间值,并实例化了更多表示所涉及的额外匿名函数的对象。