继承能够限制mixin组合目标的原因

The reason that inheritance is able to restrict mixin composition target

我知道在 trait 上使用 class 继承能够限制 class 它可以混合的内容。 这是在 mixin 时添加限制的众所周知的方法:

class Foo
trait FooTrait extends Foo
val pass = new Foo with FooTrait
class Bar
val error = new Bar with FooTrait //illegal inheritance: superclass Bar is not a subclass of the superclass Foo of the mixin trait FooTrait

abstract class Foo
trait FooTrait extends Foo
class Bar
val error = new Bar with FooTrait //illegal inheritance

Is this just the special syntax for this purpose ?

我问这个是因为我不知道如何使用继承的概念解释这个问题。 此外,如果您继承 trait 而不是 abstract class:

,我无法解释相反的结果
trait Foo
trait FooTrait extends Foo
class Bar
val pass = new Bar with FooTrait // no restriction!  

这里要理解的关键内容如下:

  1. 在 Scala 中 traits 是混入的,而不是继承的。而混入与继承有重要区别。
  2. 当你混入一个特征时,你隐含地继承了trait的超级class。

如果您的 trait 没有声明超级 class,它具有 AnyRef 的默认超级 class。

现在,如果您执行以下操作:

class Foo                  \ 1 
trait FooTrait extends Foo \ 2
class Bar extends FooTrait \ 3

第三行可以正确编译。但是当你这样做时

val bar = new Bar with FooTrait

编译失败

原因是当您使用后一种形式时,您隐式地创建了 Bar 的子class。让我试着让它更清楚一点。当您说 val bar = new Bar 时,bar 变量不是 class Bar 的实例。它是 Bar 的匿名子 class 的实例。

因此,将所有这些放在一起,当您执行类似 val bar = new Bar with FooTrait 的操作时,您实际上是在尝试创建一个具有两个超级 class 的匿名 class。两个超级classes

  1. Bar 您明确继承自
  2. Foo 您通过 Footrait
  3. 继承

JVM 不允许从多个 classes 继承,无论它们是否抽象。从多个接口继承是好的。这就是为什么你的最后一个例子:

trait Foo
trait FooTrait extends Foo
class Bar
val pass = new Bar with FooTrait // no restriction!  

编译得很好,因为特征等同于 Java 中的接口。