【发布时间】:2022-02-02 15:47:39
【问题描述】:
对不起,这个问题可能有点长,因为我想尽可能准确地描述问题和我的理解。
最近在学习 Scala 的特征系统。
我做了一些关于冲突成员的实验,见以下代码:
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 {
}
当然,这段代码编译失败了:
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 {
^
我的理解是这样的
类MyClass的线性化是{MyClass, TC, TB, TA},但是由于TB的play和TC的play上没有override,所以编译失败。
一种解决方法是在TA、TB、TC 上标记override,如下所示:
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 {
}
好的,这段代码可以按预期编译成功。
但是这个呢:
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
让我吃惊的是,这段代码也能编译成功。
类MyClass的线性化仍然是{MyClass, TC, TB, TA},并且TB的play和TC的play上没有override,唯一的区别是我添加了一个@ 987654343@ on play in MyClass。
为什么能编译成功?
请注意,Scala 不是 Java 或 C#,没有冲突成员的默认行为。
在 Java 中,如果您不将方法标记为 @Override,则默认行为是覆盖。
在 C# 中,如果您不将方法标记为 override,则默认行为是隐藏。
在 Scala 中,如果您不将方法标记为 override,则没有默认行为,它们应该是冲突的成员,IMO。
所以我觉得上面的代码编译应该是失败的,但是为什么能成功呢?
或者我的理解是错误的。
非常感谢。
【问题讨论】:
-
您在最终类中显式覆盖并精心挑选要调用的实现。固然这是合法的。这就是 mixin 的工作原理。
-
@texasbruce 但我只是在最后一个类中重写,
TB、TB和TC中的play方法仍然存在冲突。也就是说,在mixin之后,TA、TB和TC中的play方法的语义是什么?它们是override或hide或undefined?