这似乎是一个愚蠢的问题,请多多包涵...

考虑以下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中实现具体成员)。


我认为类别和特征之间的区别不会消失,主要是因为最后两项。但是,如果解决了第一点,它们可能会变得更易于使用。关于没有{}的实例化,可以添加一个方便,但是我个人不希望这样:每个实例化都会创建一个新类(一个匿名类),并且应该向程序员表明是这种情况。

关于class - 为什么Scala已经具有特征,为什么会上课?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8374992/

10-13 09:52