繁体   English   中英

为什么Scala在已经具有特征的情况下会有课程?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM