2014-03-31 34 views
10

我有一個簡單的特質,定義如下:瞭解案例類和性狀的斯卡拉

,將實現該特性
trait MyTrait { 

    def myStringVal: String 

} 

我的情況下類是如下:

case class MyCaseClass(myStringVal: String) extends MyTrait { 
    ... 
    ... 
} 

從Java世界的到來,我發現有點難以理解MyCaseClass實際上是通過爲MyCaseClass定義一個參數來實現這一點。我明白你的字節碼實際上會寫入getter和setter。但是,如果沒有任何變量或val,這怎麼可能?

我的理解是,如果沒有var或val,那麼就不會生成getter或setter方法。在那種情況下,上面的case類MyCaseClass如何實現myStringVal方法?

有時候這個Scala魔法太多了,很難理解,特別是遺留代碼。

回答

17

您可能想要查看this blog article,其中涵蓋了什麼樣的案例類,以及它們爲什麼如此有用。

在你的例子中,性狀MyTrait沒有用,除了能夠像java接口一樣工作。請注意,scala中的默認可見性是公開的。默認情況下,類參數是不可變的,所以在你的例子中val由編譯器爲myStringVal參數自動推斷。

什麼魔法做案例類嗎?

  • 轉換所有的構造參數,以公共只讀(val)由默認字段
  • 使用所有構造PARAMS爲每個方法
  • 生成與含有適當的同名伴侶對象生成toString()equals()hashcode()方法apply()unapply()方法,它們基本上只是一個便利的構造函數,允許在不使用關鍵字new和提取器的情況下實例化,該提取器默認生成case類參數的選項包裝tuple秒。

編輯:示例編譯器的輸出爲(殼體)類(從scalatutorial.de複製)

一個簡單的階類定義像

class A1(v1: Int, v2: Double) 

被編譯爲Java代碼

public class A1 extends java.lang.Object implements scala.ScalaObject { 
    public A1(int, double); 
}  

類似案例類

case class A2(v1: Int, v2: Double) 

被編譯到下面的java類

public class A2 extends java.lang.Object implements 
scala.ScalaObject,scala.Product,java.io.Serializable { 
    public static final scala.Function1 tupled(); 
    public static final scala.Function1 curry(); 
    public static final scala.Function1 curried(); 
    public scala.collection.Iterator productIterator(); 
    public scala.collection.Iterator productElements(); 
    public double copy$default$2(); 
    public int copy$default$1(); 
    public int v1(); 
    public double v2(); 
    public A2 copy(int, double); 
    public int hashCode(); 
    public java.lang.String toString(); 
    public boolean equals(java.lang.Object); 
    public java.lang.String productPrefix(); 
    public int productArity(); 
    public java.lang.Object productElement(int); 
    public boolean canEqual(java.lang.Object); 
    public A2(int, double); 
} 


public final class A2$ extends scala.runtime.AbstractFunction2 
implements scala.ScalaObject { 
    public static final A2$ MODULE$; 
    public static {}; 
    public scala.Option unapply(A2); 
    public A2 apply(int, double); 
    public java.lang.Object apply(java.lang.Object, java.lang.Object); 
} 
+0

如果我寫我自己的同伴對象爲我的案例類?我想這也是可以接受的?案例類可以擴展嗎?我想不是因爲它們是不可改變的 – sparkr

+0

編寫自己的伴侶對象應該沒問題,但我個人會使用參數的默認值。案例類本身並不是不可變的,我將用一個類/案例類的編譯器輸出更新我的答案。還沒有測試從案例類繼承 - 你需要在父類型上進行模式匹配嗎?我不是這裏的專家 - 也許別人可以進一步闡述?從特質繼承,(抽象)類等是好的。但是,您需要在案例類構造函數中指定父級的每個公共屬性。 – Floscher

0

案例類不同 - 爲它們生成一些默認方法。這包括參數的val getters。將案例類視爲POJO--這是一種有用的語法糖,因爲它們不需要私人成員。

還生成了一些其他有用的方法,例如copytoString,applyunapply

6

斯卡拉案例類有很多爲您實現的樣板類型,並且所有構造函數參數都會自動公開爲val s就是其中之一。

如果你試圖避免val S IN普通班,這樣的:

trait MyTrait { 
    def myVal: String 
} 

class MyClass(myVal: String) extends MyTrait 

編譯器會顯示錯誤信息,即MyClass的必須是抽象的,因爲它簡化版,覆蓋myVal的方法,但將valvar添加到類構造函數參數中即可解決問題。