2011-06-13 37 views
9

我有一個簡單的類層次結構代表了幾個不同類型頂點的使用情況下,類實現的圖形狀結構:更換的情況下類的繼承與提取保存全面性檢查斯卡拉

sealed trait Node 

sealed abstract case class Vertex extends Node 
case class Arc extends Node 

case class VertexType1 (val a:Int) extends Vertex 
case class VertexType2 (val b:Int) extends Vertex 

這讓我寫匹配塊是這樣的:

def test (x: Node) = x match { 
    case _ : Arc => "got arc" 
    case _ : Vertex => "got vertex" 
} 

或這樣的:

def test (x: Node) = x match { 
    case _ : Arc => "got arc" 
    case c : Vertex => c match { 
    case _ : VertexType1(a) => "got type 1 vertex " + a 
    case _ : VertexType2(a) => "got type 2 vertex " + a 
    } 
} 

請注意,此實現具有以下屬性:

1)它允許編寫區分弧和頂點但不在特定頂點類型之間的匹配塊,還可以匹配區分頂點類型的塊。

2)在這兩個頂點類型特異性和非頂點類型專用匹配塊模式匹配的窮盡被檢查。

但是,不推薦使用case類的繼承,編譯器建議使用提取器來支持非葉節點上的匹配(即,在上例中,爲了區分弧和頂點,而不是在頂點類型之間) 。

的問題:是有可能實現類似的類層次結構,而無需使用情況下類的繼承,但仍具有圖案全面性如上所示通過在這兩種情況下,使用編譯器執行檢查?

編輯:我已經向VertexType類添加了一個構造函數參數,以便匹配不僅僅在類型上執行。

我沒有case類目前實現如下:

sealed trait Node 

sealed abstract class Vertex extends Node 
class Arc extends Node 

class VertexType1 (val a:Int) extends Vertex 
class VertexType2 (val b:Int) extends Vertex 

object VertexType1 { 
    def unapply (x : VertexType1) : Some[Int] = Some(x.a) 
} 

object VertexType2 { 
    def unapply (x : VertexType2) : Some[Int] = Some(x.b) 
} 

並測試代碼:

def test (x: Node) = x match { 
    case _ : Arc => "got arc" 
    case v : Vertex => v match { 
    case VertexType1(a) => "got vertex type 1 " + a 
    } 
} 

我期待有一個關於非詳盡的比賽在第二塊警示(VertexType2是從來沒有匹配),但沒有一個。

實際上,在2.9.0-RC3之前的Scala編譯器產生了一個我期望看到的警告,但是以RC3開頭的版本(包括2.9.0和2.9.0-1)沒有,這相當混亂。

+1

倍數:這已被固定在斯卡拉2.10。 (在Scala 2.9.x中出現了迴歸) – gourlaysama 2013-01-31 16:16:51

回答

0

從scala-lang.org引證:

如果模式匹配的選擇器是一個密封類的一個實例,模式匹配的彙編可以發射其診斷出一組給定的警告模式並不詳盡,即有在運行時提出了MatchErrorbeing的可能性。

2

提取器爲您提供了在模式匹配中使用它的可能性,例如scala中的case類,但它們在使用case修飾符時沒有其他標準實現。 但華中科技大學這些額外的實現(特別是平等的實現)是什麼使情況類繼承危險的,所以它得到了否決。

然而密封類是正交功能,你可以使用他們,你是否擁有一個案例類或提取。通過使用提取器,您不會即時獲得標準實現,因此您可以繼承提取器 - 它們只是具有unapply和/或unapplySeq方法的普通類。

......你在你的例子做了什麼叫做在類型模式匹配。如果你只想做到這一點,你不需要案例類,也不需要提取器。你可以用你想要的每一堂課來完成。所以你可以簡單地刪除大小寫修飾符。

因此得出結論:圖案的全面性是由密封類hirachies實現。模式匹配是通過提取器和案例類來實現的,後者只是一個具有吸引力的常用函數標準實現的提取器。 我希望這有助於。

+1

很好的答案,但是請多閱讀一遍,以便了解許多錯別字。謝謝! – 2011-06-13 19:19:52

+0

非常感謝你的回答,我不知道窮舉是通過密封層次結構實現的,而不是通過case修飾符實現的。但是,如果我將模式匹配擴展到匹配類型之外(我已經將這個更正添加到原始問題),我仍然會得到意想不到的行爲,事實證明,這取決於編譯器版本:( – 2011-06-13 19:45:03

2

一般來說,這是不能做到的。

密封類是因爲scalac知道在編譯的時候很多比賽是如何可能的特殊情況(沒有雙關語意)。

但由於提取允許您運行任意代碼,並因爲該死的停機問題,有沒有辦法讓編譯器中,你會檢查每一個案件任何情況下保證。試想一下:

def test(foo: Int) { 
    foo match { 
    case IsMultipleOf8(n) => printf("%d was odd\n", n) 
    } 
} 

這還不全面,因爲它不處理不屬於8的倍數的數字,但是編譯器不能推斷(不上的所有Int的運行您的提取器),只有類型的某些值Int是出於完整性8.

+1

是的,當然在一般情況下這是真的,但在我的例子中,提取器對象總是返回一些東西(因爲它的返回類型是Some [Int]而不是Boolean或Option),所以保證匹配不會失敗(也就是說,如果最終的unapply方法終止,我認爲這是一個合理的假設)因此唯一需要檢查的是覆蓋層次結構中的所有類型注意,編譯器能夠將匹配的值(類型爲Node)隱式轉換爲提取器接受的具體類型,所以它知道層次結構。 – 2011-06-14 14:24:57