[英]Why does Scala have classes when it already has traits?
這似乎是一個愚蠢的問題,所以請耐心等待......
考慮一下這個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 = $anon$1@78db81f3
scala> class C
defined class C
scala> val c = new C
c: C = C@170a6001
我們可以像使用類一樣使用特征,除了我們必須在new T
之后添加{}
。 實際上,我們實際上是將T
混合到java.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 = $anon$1@6a688d6f
scala> t2.s
res0: java.lang.String = test
scala> class C2 { val s = "test" }
defined class C2
scala> val c2 = new C2
c2: C2 = C2@73ea7821
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 = $anon$1@1f2f0ce9
scala> abstract class C3 { val s: String }
defined class C3
scala> val c3 = new C3 { val s = "test" }
c3: C3 = $anon$1@207a8313
如果您忘記必須定義一些成員,則兩種方式都會給您編譯錯誤:
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 = $anon$1@479e0994
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
所以我再次問,為什么當特征顯然更簡單,更強大時,Scala會對課程感到困擾?
我假設原因是與Java的概念和實際兼容性,但我想知道是否可以在幕后維護代碼兼容性。 據我所知,Scala特性只是在幕后成為Java類,為什么不能反過來發生Scala認為Java類本質上是特征?
與此相關,為什么不允許在不必要時刪除大括號? 例如:
val t = new T
此時, 作為用戶 ,特征與當前的Scala類無法區分,但當然更好。
特征和類之間有幾個不同之處:
特征不能采用構造函數參數。 這個限制可能會在某個時候解除,但這是一個難題。 特征可以在層次結構中多次繼承,並且每個實例化可以為構造函數參數提供不同的值
特征被編譯為Java接口和實現類(攜帶具體方法)。 這意味着它有點慢,因為所有調用都通過接口,如果它們是具體的,它們將被轉發到它們的實現
具體成員的特征不能在Java中很好地繼承(它可以,但它看起來像一個接口,因此具體成員仍然需要用Java實現)。
我不認為類和特征之間的區別會消失,主要是因為最后兩項。 但如果第一點得到解決,它們可能會變得更容易使用。 關於沒有{}
實例化,這是一個可以添加的便利,但我個人不喜歡它:每個實例化創建一個新類 (一個匿名的),並且應該向程序員表明情況就是這樣。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.