2014-03-31 27 views
3

我剛剛嘗試了下面的這段代碼,它按預期工作。它打印1。我的問題是,我不明白髮生了什麼。爲案例類合併定製和編譯器生成的伴隨對象。合併規則是什麼?

case類如何有兩個伴隨對象(一個由編譯器生成,另一個由我編寫)?可能它不能。所以他們必須以某種方式合併在引擎蓋下。我只是不明白他們如何合併?我應該注意哪些特殊的合併規則?

是這樣的,如果兩個伴隨對象中定義的定義集合是不相交的,那麼結果案例類別中的定義集合就是兩個不相交集合的並集?我會認爲這是他們如何合併,但我不確定。有人可以確認這個合併規則是否是在Scala編譯器中實現的規則?還是有什麼額外的呢?

更具體地說,什麼由編譯器產生的配對對象和我的同伴對象是合併規則?這些規則是否在某處指定?

我還沒有真正看到過這個話題,在我閱讀過的幾本Scala書中討論過 - 也許表面看起來太過膚淺。

object A{ 
    implicit def A2Int(a:A)=a.i1 
} 
case class A(i1:Int,i2:Int) 

object Run extends App{ 
    val a=A(1,2) 
    val i:Int=a 
    println(i) 
} 

回答

2

我不知道在哪裏的算法自動合併和明確的同伴對象描述或記錄(比編譯器源等),但通過編譯代碼,然後檢查所生成的同伴對象(使用javap的) ,我們可以看到有什麼不同(這與scala 2.10.4有關)。

下面是case類生成的同伴對象(沒有你額外的同伴對象):

Compiled from "zip.sc" 
    public final class A$ extends scala.runtime.AbstractFunction2<Object, Object, A> implements scala.Serializable { 
    public static final A$ MODULE$; 
    public static {}; 
    public A apply(int, int); 
    public scala.Option<scala.Tuple2<java.lang.Object, java.lang.Object>> unapply(A); 

    public java.lang.Object apply(java.lang.Object, java.lang.Object); 
    public final java.lang.String toString(); 
    } 

加入你的同伴對象後,這裏會產生什麼:

Compiled from "zip.sc" 
    public final class A$ implements scala.Serializable { 
    public static final A$ MODULE$; 
    public static {}; 
    public A apply(int, int); 
    public scala.Option<scala.Tuple2<java.lang.Object, java.lang.Object>> unapply(A); 
    public int A2Int(A); 
    } 

的差異生成的伴侶對象由顯式伴侶對象定義引起的似乎爲:

  1. 它不再延長AbstractFunction2
  2. 它不再有工廠方法(適用)有關子彈1
  3. 它不再覆蓋toString方法(我假設你預計供應一個,如果需要的話)
  4. 您A2Int方法添加

如果案件類改爲普通類(連同得到它來編譯所需最小的變化),其結果如下:

Compiled from "zip.sc" 
    public final class A$ { 
    public static final A$ MODULE$; 
    public static {}; 
    public A apply(int, int); 
    public int A2Int(A); 
    } 

所以,如果你聲明你自己的伴侶對象,至少在這個簡單的例子中,效果是你的新方法被添加到伴隨對象中,並且它的一些實現和功能也會丟失。如果我們試圖覆蓋一些剩餘的自動生成的東西,但是剩下的不多,會發生什麼情況會很有趣,所以一般情況下不太可能導致衝突。

case類的一些優點與生成的代碼無關,例如公開類變量而不必顯式添加'val'關鍵字。以下是上述所有3個反編譯示例的修改源代碼。

版本1(沒有明確的同伴對象):

case class A(i1:Int,i2:Int) 

2版是您的原始版本。

版本3(任何情況下級):

object A { 
    implicit def A2Int(a:A)=a.i1 
    def apply(a:Int,b:Int):A = new A(a,b) 
} 
class A(val i1:Int,val i2:Int) 

object Run extends App{ 
    import A._ 
    val a=A(1,2) 
    val i:Int=a 
} 

在3版本,我們需要VAL添加到A級參數(否則它們是私有的),我們必須以添加工廠方法到我們的伴侶對象,或者在創建A(1,2)的實例時使用'new'關鍵字。