Trait mixin 与冲突的成员:为什么我的代码可以成功编译?

cha*_*sey 5 oop scala

抱歉,这个问题可能有点长,因为我想尽可能准确地描述问题和我的理解。

最近在学习Scala的trait系统。

我对冲突成员做了一些实验,见以下代码:

trait TA {
  def play() = println("TA play")
}

trait TB {
  def play() = println("TB play")
}

trait TC {
  def play() = println("TC play")
}

class MyClass extends TA with TB with TC {
}
Run Code Online (Sandbox Code Playgroud)

当然,这段代码按照预期编译失败了:

Error:(13, 8) class MyClass inherits conflicting members:
  method play in trait TB of type ()Unit  and
  method play in trait TC of type ()Unit
(Note: this can be resolved by declaring an override in class MyClass.)
class MyClass extends TA with TB with TC {
      ^
Run Code Online (Sandbox Code Playgroud)

我的理解是

class 的线性化为MyClass{MyClass, TC, TB, TA}但由于没有overrideof和of ,所以编译失败playTBplayTC

一种解决方法是标记overrideTATBTC如下所示:

trait IPlay {
  def play()
}

trait TA extends IPlay {
  override def play() = println("TA play")
}

trait TB extends IPlay {
  override def play() = println("TB play")
}

trait TC extends IPlay {
  override def play() = println("TC play")
}

class MyClass extends TA with TB with TC {
}
Run Code Online (Sandbox Code Playgroud)

OK,这段代码果然可以编译成功了。

但是这个呢:

trait TA {
  def play() = println("TA play")
}

trait TB {
  def play() = println("TB play")
}

trait TC {
  def play() = println("TC play")
}

class MyClass extends TA with TB with TC {
  override def play(): Unit = {
    println("MyClass play")
    super.play()
    super[TC].play()
    super[TA].play()
    super[TB].play()
  }
}

(new MyClass).play()

// -- Output:
// MyClass play
//   TC play
//   TC play
//   TA play
//   TB play
Run Code Online (Sandbox Code Playgroud)

让我惊讶的是这段代码也能编译成功。

class 的线性化仍然MyClass是,{MyClass, TC, TB, TA}并且没有overrideon和the ,唯一的区别是我在 中添加了一个on 。playTBplayTCoverrideplayMyClass

为什么可以编译成功呢?

请注意,Scala 不是 Java 或 C#,不存在冲突成员的默认行为。

在 Java 中,如果不将方法标记为@Override,则默认行为是覆盖。

在 C# 中,如果不将方法标记为override,则默认行为是隐藏。

在 Scala 中,如果您不将方法标记为override,则没有默认行为,它们应该是冲突的成员,IMO。

因此,我认为上面的代码编译应该是失败的,但是为什么能够成功呢?

或者我的理解是错误的。

很感谢。

小智 1

您已在子类中手动定义行为。\n您为什么感到惊讶?在这种情况下,什么是不正确的?

\n

我认为示例中主要令人困惑的事情是 \xe2\x80\x9csuper.play()\xe2\x80\x9d 是合法的,并且与最后一个继承的成员 - TC 相关。我认为这只是我们只采用最后一个时的解决方法。\n我想他们可以通过此解决方法解决第一种情况(不\xe2\x80\x99t 编译) - 只需采用最后一个继承的实现。

\n