話說模式匹配(6) case類的細節
我們在第二篇文章裡曾提到過:
本質上case class是個語法糖,對你的類構造引數增加了getter訪問,還有toString, hashCode, equals 等方法; 最重要的是幫你實現了一個伴生物件,這個伴生物件裡定義了
apply
方法和unapply
方法。
現在我們來詳細的分析一下case class
,對一個簡單的樣本類
case class B()
反編譯後看到編譯器自動給它混入了Product
特質,以及Serializable
特質:
public class B implements scala.Product,scala.Serializable { public B copy(); public java.lang.String productPrefix(); public int productArity(); public java.lang.Object productElement(int); public scala.collection.Iterator<java.lang.Object> productIterator(); public boolean canEqual(java.lang.Object); public int hashCode(); public java.lang.String toString(); public boolean equals(java.lang.Object); public B(); }
再看看它的半生物件:
//伴生物件也混入了AbstractFunction0 和 Serializable 特質 public final class B$ extends scala.runtime.AbstractFunction0<B> implements scala.Serializable { public static final B$ MODULE$; public static {}; public final java.lang.String toString(); public B apply(); public boolean unapply(B); public java.lang.Object apply(); }
通過反編譯的結果我們瞭解到了幾點:
- 編譯器對case類混入了
Product
特質 - 編譯器對case類增加了
copy
方法; - 編譯器對case類實現了
equals/hashCode/toString
等方法 - 伴生物件中最重要的方法是 unapply 這個方法是在進行構造器模式匹配時的關鍵。
- 伴生物件中
apply
方法則為建立物件提供方便,相當於工廠方法。 - 伴生物件繼承了
AbstractFunction
從case類的設計目的來看,最重要的是提供構造器模式匹配(且構造時的引數,與解構的結果一致),另外case類可看作是資料物件,不可變的資料物件。
因為case類封裝的資料有不變的特點,以及可以進行模式匹配,所以它在actor中經常使用,很適合封裝訊息在actor之間傳遞。
上面列出的幾點中,對於第6點“伴生物件繼承自 Function”可能感到奇怪,Martin在這裡回答了為什麼case類的伴生物件會繼承FunctionN
The reason why case class companion objects implement FunctionN is that before, case classes generated a class and a factory method, not a companion object. When we added extractors to Scala it made more sense to turn the factory method into a full companion object with apply and unapply methods. But then, since the factory method did conform to FunctionN, the companion object needed to conform, too.
另外,當引數大於2個時,FunctionN 都提供了tupled方法生成一個函式,該函式可以接受一個tuple作為引數構造出結果,比如:
scala> case class A(x: Int, y:Int)
scala> A.tupled
res11: ((Int, Int)) => A = <function1>
scala> val t = (100,100)
t: (Int, Int) = (100,100)
scala> A.tupled(t)
res9: A = A(100,100)