gpt4 book ai didi

scala - 特征混合与冲突成员 : Why my code can be compiled successfully?

转载 作者:行者123 更新时间:2023-12-03 21:49:28 25 4
gpt4 key购买 nike

对不起,这个问题可能有点长,因为我想尽可能准确地描述问题和我的理解。
最近我在学习 Scala 的 trait system。
我做了一些关于冲突成员的实验,看下面的代码:

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} ,但由于没有 overrideplayTBplayTC ,所以编译失败。
一种解决方法是标记 overrideTA , TB , TC ,如下:
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 {
}
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
令我惊讶的是,这段代码也可以编译成功。
类的线性化 MyClass还是 {MyClass, TC, TB, TA}并且没有 overrideplayTBplayTC ,唯一不同的是我加了一个 overrideplayMyClass .
为什么可以编译成功?
请注意,Scala 不是 Java 或 C#,冲突成员没有默认行为。
在 Java 中,如果不将方法标记为 @Override ,默认行为是覆盖。
在 C# 中,如果不将方法标记为 override ,默认行为是隐藏。
在 Scala 中,如果您不将方法标记为 override ,没有默认行为,他们应该是冲突的成员,IMO。
所以,我觉得上面的代码编译应该是失败的,但是为什么可以成功呢?
或者我的理解是错误的。
很感谢。

最佳答案

太看潜在冲突从何而来,我们需要采纳MyClass的“观点” .
让我们回顾一下您的示例,看看为什么会得到这些结果(为了简化,我将使用 2 个特征而不是 3 个特征)。
第一个例子:通常的冲突

trait TA { def play() = println("TA") }
trait TB { def play() = println("TB") }
class MyClass extends TA with TB {}
这失败了,因为这两个特征都定义了 play具有相同签名的方法,但不清楚该选择哪一个 MyClass.play .有人可能会争辩说“编译器可以选择 TB.play 因为它是最后一个混合特征”,但是由于没有声明要覆盖某些东西的意图,Scala 拒绝了它。原则上是可以的,但是 Scala 团队选择强制你更清楚地表达你的意图。
怎么做?
明确意图 1:在 trait 中覆盖
trait T { def play(): Unit }
trait TA { override def play() = println("TA") }
trait TB { override def play() = println("TB") }
class MyClass extends TA with TB {}
您的第二个示例显示了表达覆盖意图的一种方式。自 TA.playTB.playoverride 声明,很明显他们打算覆盖方法 play(): Unit这在范围内。这就是为什么编译器允许 TB.play “替换” TA.playMyClass .
明确意图2:在类里面覆盖
class MyClass extends TA with TB {
override def play(): Unit = {
super.play() // super[TB].play()
super[TA].play()
}
}
覆盖类中的方法是解决问题的另一种方法。在这里我们确切地知道什么 MyClass.play是,因为它是明确定义的。从 MyClass的角度来看没有歧义。
编译器可以使用 super[TA].play()因为很清楚调用哪个方法:在 trait TA 中定义的方法来自 def play() = println("TA") .所以 super[TA].play()将执行 println("TA") . super.play()不太明确,但类组成的规则很明确: super在此上下文中指的是最后一个 mixin,即它与 super[TB] 相同.

关于scala - 特征混合与冲突成员 : Why my code can be compiled successfully?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63234908/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com