2013-01-25 137 views
2

我有我要做的模式匹配對後來以下數據模型:斯卡拉圖案匹配的結構

abstract class A 
case class C(s:String) extends A 

abstract class B extends A 
case class D(i:Int) extends B 
case class E(s:Int, e:Int) extends B 

A是層次的抽象的超類型。 C是A的一個具體子類A的其它具體子類是B的又A.

的子類的子類,現在,如果我寫這樣的事情,它的工作原理:

def match(a:A) a match { 
    a:C => println("C") 
    a:B => println("B") 
} 

然而,在for循環中,我不能對陣B.我認爲我需要一個構造格局,但由於B是抽象的,有一個B.

val list:List[A] = List(C("a"), D(1), E(2,5), ...) 

for (b:B <- list) println(b) // Compile error 
for ([email protected] <- list) println(b) // Compile error 

這裏沒有構造模式,我想打印僅有B實例。針對這種情況的任何解決方法?

回答

2

您可以使用collect

list.collect { case b: B => println(b) } 

如果你想更好地undertand此,我建議閱讀部分功能。例如,Here

+0

如何使用收集需要嵌套迭代時,我使用的首要原因是,是具有人另一種類型的X? As的。所以,我想這樣寫: '類X(名稱:字符串,如:列表[A])' 'LISTX = ... //一個X' 的列表爲'(X < - LISTX; b:B < - X.as')println(b) 當然,我可以在兩個步驟中使用for和收集,但我想知道是否有一個單行的解決方案... – Wickoo

+0

@Ali :請參閱我的答案,以另一種方式來做到這一點,按照您的要求使用理解。 –

2

謝爾蓋是對的;如果您想要模式匹配並僅篩選B實例,則必須放棄for。如果您仍然想使用for理解是什麼原因,我認爲一個人的方式就是訴諸使用保護:

for (b <- list if b.isInstanceOf[B]) println(b) 

但它總是挑選最好的,模式匹配,而不是isInstanceOf。所以我會去與collect建議(如果它在我的代碼的其餘部分的情況下是有道理的)。

另一個建議是定義一個同伴對象B具有相同的名稱,並定義unapply方法:

abstract class A 
case class C(s:String) extends A 

abstract class B extends A 
object B { def unapply(b: B) = Option(b) } // Added a companion to B 
case class D(i:Int) extends B 
case class E(s:Int, e:Int) extends B 

然後,你可以這樣做:

for (B(b) <- list) println(b) 

所以這是不是B的'構造函數',而是伴侶的方法unapply。 它的作品,這就是朋友的用途,對吧?

(見http://www.scala-lang.org/node/112

0

我的2美分:您可以在添加條件修真檢查類型,但會是優雅與使用collect其將採取B類的實例只

2

如果你問我,這裏你不能使用模式匹配的事實是scala的一個不幸的不一致性。事實上階確實讓你在推導模式匹配,如以下示例將顯示:

val list:List[A] = List(C("a"), D(1), E(2,5) 
for ((b:B,_) <- list.map(_ -> null)) println(b) 

在這裏,我暫時包裹元件到雙(蒙山虛設和未使用的第二值),然後模式匹配對的一對其中第一個元素是B型的作爲輸出顯示,你會得到預期的行爲:

D(1) 
E(2,5) 

所以你去,斯卡拉做基於模式匹配支持過濾(按類型匹配,即使)它似乎只是語法沒有ndle模式按類型匹配單個元素。

顯然我不建議使用這個技巧,這只是爲了說明。使用collect肯定更好。

話又說回來,還有另一個更普遍的解決方案,如果由於某種原因,你真的看中的內涵比什麼都重要:

object Value { 
    def unapply[T](value: T) = Some(value) 
} 
for (Value(b:B) <- list) println(b) 

我們剛剛介紹了Value對象,只是什麼都不做的假人提取,所以Value(b:B)b:B的含義相同,只是前者編譯。而且不像我之前的配對技巧,它比較可讀,並且只需要編寫一次,你可以隨意使用它(特別是,不需要爲每個你想要模式匹配的類型編寫一個新的提取器,在@ Faiz的答案中,我會讓你找到一個比Value更好的名字

最後,還有另外一個解決方法,即開箱即用(信用評價到Daniel Sobral),但它的可讀性稍差需要一個虛擬的標識符(這裏foo):

for (b @(foo:B) <- list) println(b) 
// or similarly: 
for (foo @(b:B) <- list) println(b) 
+0

謝謝!我同意你的觀點,即不能使用'理解'中的類型來匹配匹配,但最終我認爲我會去收集,至少我不必介紹其他的東西。 – Wickoo

+0

好戲,它對我來說是新的:) –

+0

我增加了另一項工作,由Daniel Sobral在另一個問題中提出 –