2014-08-27 254 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]} 

醜陋的事情應該看起來很醜陋。