2011-12-04 64 views
16

這似乎是一個愚蠢的問題,所以我承擔......爲什麼Scala在已經有特徵的時候就已經上課了?

考慮這個REPL會話:

scala> trait T 
defined trait T 

scala> val t = new T 
<console>:8: error: trait T is abstract; cannot be instantiated 
     val t = new T 
      ^

scala> val t = new T {} 
t: java.lang.Object with T = [email protected] 

scala> class C 
defined class C 

scala> val c = new C 
c: C = [email protected] 

我們可以用一個特質,就像一類,但我們必須添加{}之後的new T。事實上,我們基本上混合了Tjava.lang.Object,這實際上對我很有意義。

如果我們的成員,再次只有{}必須添加:

scala> trait T2 { val s = "test" } 
defined trait T2 

scala> val t2 = new T2 
<console>:8: error: trait T2 is abstract; cannot be instantiated 
     val t2 = new T2 
       ^

scala> val t2 = new T2 {} 
t2: java.lang.Object with T2 = [email protected] 

scala> t2.s 
res0: java.lang.String = test 

scala> class C2 { val s = "test" } 
defined class C2 

scala> val c2 = new C2 
c2: C2 = [email protected] 

scala> c2.s 
res1: java.lang.String = test 

如果我們有抽象成員則性狀聲明是由幾個字符實際上更短,更重要的是,在我的眼中更加一致(不需要記得把abstract在聲明前):

scala> trait T3 { val s: String } 
defined trait T3 

scala> val t3 = new T3 { val s = "test" } 
t3: java.lang.Object with T3 = [email protected] 

scala> abstract class C3 { val s: String } 
defined class C3 

scala> val c3 = new C3 { val s = "test" } 
c3: C3 = [email protected] 

如果你忘了,你必須定義一些成員,左右逢源給你編譯錯誤:

scala> val badt3 = new T3 {} 
<console>:7: error: object creation impossible, since value s in trait T3 of type String is not defined 
     val badt3 = new T3 {} 

scala> class BadC3 { val s: String } 
<console>:8: error: class BadC3 needs to be abstract, since value s is not defined 
     class BadC3 { val s: String } 

如果我們試圖做更復雜的事情,然後性狀的力量自然變得更加明顯:

scala> val t4 = new T with T2 
t4: java.lang.Object with T with T2 = [email protected] 

scala> val c4 = new C with C2 
<console>:9: error: class C2 needs to be a trait to be mixed in 
     val c4 = new C with C2 

所以我再次問,爲什麼斯卡拉帶班懶得在所有的時候特質顯然是既更簡單,更強大?

我假設原因是Java的概念性和實際兼容性,但我想知道代碼兼容性是否可以在幕後維護。據我瞭解,斯卡拉特質只是在幕後成爲Java類,所以爲什麼不能發生逆轉,Scala認爲Java類實質上是特質?

與此相關的是,爲什麼不允許在不必要時丟棄大括號?例如:

val t = new T 

在這一點上,作爲用戶,性狀是由目前的Scala類沒有區別,但當然更好。

+2

你寫的每一次'新款T {}'你創建一個新的匿名類。不是那種你想要的開銷。此外,'T'的幾個「實例」將不會具有相同的類型。 – Raphael

回答

29

有特質和類之間的一些差異:

  • 的性狀不能把構造函數的參數。這個限制可能會在某些時候被解除,但這是一個難題。一個特徵可以在層次結構中被多次繼承,並且每個實例化可以爲構造參數提供不同的值。特徵被編譯爲Java接口和實現類(攜帶具體方法)。這意味着它會慢一點,因爲所有的調用都要經過接口,如果它們是具體的,它們會被轉發到它們的實現。

  • 具有具體成員的特性不能在Java中很好地繼承(它可能,但它看起來像一個接口,因此具體成員仍然需要在Java中實現)。

我不認爲類和性狀之間的區別會去,因爲最後兩個項目的大多了,。但如果第一點解決了,它們可能會變得更容易使用。對於沒有{}實例,這是可以添加一個方便的,但我個人不喜歡它:每個實例創建一個新的(匿名的),並且應該有一個指示,即是這樣的情況下,程序員。

+0

很好的解釋,謝謝。 – pr1001

+1

請注意,HotSpot(至少)將執行類型銳化。由於這些特徵將變成只有1個實現的接口,那些對trait方法的調用將從invokeinterface調入invokevirtual。因此,對於方法調用速度較慢的評論可能不適用於大多數情況。 – kittylyst

+0

@kittylyst,你是對的JVM。但是,特徵有很多實現(從JVM的角度來看)。每當一個特徵混入一個類中時,相應的接口就會被該類重新實現。對於性能相對較少的長時間運行的應用程序,其方法可能樂觀地內聯,但至少啓動時間會受到影響。我在哪裏可以閱讀更多關於Type Sharpening的信息? –

相關問題