2014-08-27 102 views
6

假设我有下面的类层次结构:模式匹配或isInstanceOf斯卡拉

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 

它工作是否一样?你更喜欢什么?

回答

11

为什么不使用collect?具有额外的好处返回的列表将是正确的类型(列表[A1]而不是List [A])

val a1s = as.collect { case x:A1 => x } 
+0

感谢提醒我关于'collect'? – Michael 2014-08-27 15:14:33

+0

这也适用于匹配Java类型,而不仅仅是Scala类型(从2.11.4开始测试) – 2014-12-16 21:38:10

1

它的工作原理一样吗?

将生成相同的答案,但不同的代码将在每种情况下发出,如您所料。

您可以检查每种情况下生成的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 

为了检验IL为as.filter(cond(_){case _: A1 => true})版本,请

javap -c 'Filterer$$anonfun$filter1$1' 
javap -c 'Filterer$$anonfun$filter1$1$$anonfun$apply$1' 

然后检查IL对于as.filter(_.isInstanceOf[A1])版本,您可以做

javap -c 'Filterer$$anonfun$filter2$1' 

cond”版本使用更多中间值并实例化更多表示所涉及的额外匿名函数的对象。

6

尽管接受的答案为您提供了一个很好的建议,但请注意,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]} 

丑陋的事情应该看起来很丑陋。