我在Google中搜索了case class
和class
之間的區別。 每一個人都提到,當您要在類上進行模式匹配時,請使用用例類。 不然,使用類,還說起一些額外的好處,例如equals和哈希碼覆蓋。 可是,這些是爲何應該使用案例類而不是類的惟一緣由嗎? app
我猜應該在Scala中使用此功能有一些很是重要的緣由。 有什麼解釋?是否有資源能夠從中學習更多有關Scala案例類的信息? 函數
沒有人提到案例類具備val
構造函數參數,但這也是常規類的默認值( 我認爲這在Scala的設計中是不一致的)。 達里奧(Dario)在他指出它們「 不可變 」的地方暗示了這一點。 學習
請注意,您能夠經過爲案例類在每一個構造函數參數前添加var
來覆蓋默認值。 可是,使案例類可變則會致使其equals
和hashCode
方法具備時變性。[1] 優化
sepp2k已經提到案例類自動生成equals
和hashCode
方法。 spa
也沒有人提到案例類自動建立與該類同名的伴隨object
,其中包含apply
和unapply
方法。 apply
方法能夠構造實例,而無需添加new
。 在unapply
提取方法使圖案匹配,其餘人說起。 設計
另外,編譯器還優化了match
速度-案例類的case
模式匹配[2]。 code
[1] 案例類別很酷 orm
[2] 案例分類和提取器,第15頁 。 對象
案例類能夠看做是普通且不可變的數據保存對象,應僅取決於其構造函數參數 。 繼承
這個功能概念使咱們可以
Node(1, Leaf(2), None))
) 與繼承結合使用,case類用於模擬代數數據類型 。
若是對象在內部執行狀態計算或表現出其餘複雜的行爲,則應爲普通類。
(您已經提到了除最後一個之外的全部內容)。
這些是普通班級的惟一區別。
從技術上講,類和案例類之間沒有區別-即便編譯器在使用案例類時確實優化了某些內容。 可是,案例類用於取消特定模式的樣板,該特定模式正在實現代數數據類型 。
這種類型的一個很是簡單的例子是樹。 例如,能夠像這樣實現一個二叉樹:
sealed abstract class Tree case class Node(left: Tree, right: Tree) extends Tree case class Leaf[A](value: A) extends Tree case object EmptyLeaf extends Tree
這使咱們可以執行如下操做:
// DSL-like assignment: val treeA = Node(EmptyLeaf, Leaf(5)) val treeB = Node(Node(Leaf(2), Leaf(3)), Leaf(5)) // On Scala 2.8, modification through cloning: val treeC = treeA.copy(left = treeB.left) // Pretty printing: println("Tree A: "+treeA) println("Tree B: "+treeB) println("Tree C: "+treeC) // Comparison: println("Tree A == Tree B: %s" format (treeA == treeB).toString) println("Tree B == Tree C: %s" format (treeB == treeC).toString) // Pattern matching: treeA match { case Node(EmptyLeaf, right) => println("Can be reduced to "+right) case Node(left, EmptyLeaf) => println("Can be reduced to "+left) case _ => println(treeA+" cannot be reduced") } // Pattern matches can be safely done, because the compiler warns about // non-exaustive matches: def checkTree(t: Tree) = t match { case Node(EmptyLeaf, Node(left, right)) => // case Node(EmptyLeaf, Leaf(el)) => case Node(Node(left, right), EmptyLeaf) => case Node(Leaf(el), EmptyLeaf) => case Node(Node(l1, r1), Node(l2, r2)) => case Node(Leaf(e1), Leaf(e2)) => case Node(Node(left, right), Leaf(el)) => case Node(Leaf(el), Node(left, right)) => // case Node(EmptyLeaf, EmptyLeaf) => case Leaf(el) => case EmptyLeaf => }
請注意,樹使用相同的語法構造和解構(經過模式匹配),這也正是它們的打印方式(減去空格)。
而且它們還能夠與哈希映射或集一塊兒使用,由於它們具備有效,穩定的hashCode。
Scala中的case類構造也能夠看做是刪除某些樣板的便利。
在構造案例類時,Scala爲您提供瞭如下內容。
apply
方法。 您將得到沒必要使用new關鍵字的語法優點。
因爲該類是不可變的,所以您將得到訪問器,這些訪問器僅是該類的變量(或屬性),而沒有變種器(所以沒法更改變量)。 構造函數參數能夠做爲公共只讀字段自動提供給您。 比Java bean構造好用得多。
hashCode
, equals
和toString
方法,而且equals
方法在結構上比較對象。 生成copy
方法以可以克隆對象(某些字段具備提供給該方法的新值)。 如前所述,最大的優點是您能夠在案例類上進行模式匹配。 這樣作的緣由是由於您得到了unapply
方法,該方法使您能夠解構case類以提取其字段。
從本質上講,在建立案例類(或案例對象,若是您的類不帶參數)時從Scala得到的內容是單例對象,其目的是用做工廠和提取器 。