对于下面的代码,因为我理解表达式的线性化
新E与D与C与B
是E - > C - > B - > D.那么在代码
中不应该使用表达式d.foo()下面评估ECBD而不是CBDE。我错过了什么?
trait A {
def foo(): String = ""
}
trait B extends A {
abstract override def foo() = "B" + super.foo()
}
trait C extends B {
abstract override def foo() = "C" + super.foo()
}
trait D extends A {
abstract override def foo() = "D" + super.foo()
}
class E extends A{
override def foo() = "E"
}
var d = new E with D with C with B;
d.foo() //prints CBDE
我注意到如果我有一个类F,如下所示
class F extends A with D with C with B{
override def foo() = "F" + super.foo()
}
并做
new F().foo
打印“FCBD”
对我来说似乎有点不一致,因为F类与表达式的混合方式相同但打印顺序不同
答案 0 :(得分:5)
new E with D with C with B
的第一个案例完美地解释了here。它的线性化为EDBC
,因此当您调用d.foo()
时,它就是
C#foo()
,B#foo()
,D#foo()
E#foo()
。 如果您将E
作为特征并将其混合到最后:val d = new D with C with B with E
,则d.foo()
将仅返回"E"
,因为特征E
是"最后"在线性化中,只是覆盖foo
。
F
的情况不同,因为您将foo
定义为"F" + super.foo()
,而super
在这种情况下为A with D with C with B
,其线性化为{{1}所以ADBC
- 首先打印new F().foo()
,
- 然后是"F"
super.foo()
。
顺便说一下,尝试更改"CBD"
以返回A#foo()
,然后您会在"A"
中看到您覆盖A E
所以{{1} }并不会出现在结果中,而foo
中只有"A"
。
答案 1 :(得分:1)
所以让我们添加一些行来显示实例化顺序
trait A {
print("A")
def foo(): String = "A"
}
trait B extends A {
print("B")
abstract override def foo() = "B" + super.foo()
}
trait C extends B {
print("C")
abstract override def foo() = "C" + super.foo()
}
trait D extends A {
print("D")
abstract override def foo() = "D" + super.foo()
}
class E extends A {
print("E")
override def foo() = "E" + super.foo()
}
var e = new E with D with C with B
println()
println(s"e >> ${e.foo()}")
打印:
AEDBC
e >> CBDEA
但是F
怎么办?
class F extends A with D with C with B {
print("F")
override def foo() = "F" + super.foo()
}
val f = new F()
println()
println(s"f >> ${f.foo()}")
打印:
ADBCF
f >> FCBDA
因为您可以看到两种情况的线性化都不一样! 当我们使用一系列特性来实例化该类时,与创建一个继承这些特性的单独类时并不相同。
因此,根据线性化,调用foo
的顺序也不同。
当我们将super.foo()
添加到E