Scala 可堆叠特征
Scala stackable traits
根据我的理解,下面的代码是表达式的线性化
新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
我注意到如果我有一个像下面这样的 class F
class F extends A with D with C with B{
override def foo() = "F" + super.foo()
}
并做
new F().foo
它打印 "FCBD"
这对我来说似乎有点不一致,因为class F 的混合方式与表达式相同,但打印顺序不同
第一种情况new E with D with C with B
完美解释。它的线性化是EDBC
,所以当你调用d.foo()
时,它
- 第一次调用
C#foo()
、
- 然后
B#foo()
、
- 然后
D#foo()
- 最后
E#foo()
。
如果你让E
成为一个特质,最后将其混合:val d = new D with C with B with E
,那么d.foo()
将return只是"E"
,因为特质E
是线性化中的 "last" 并且只是覆盖 foo
.
F
的情况不一样,因为你把foo
定义为"F" + super.foo()
,而super
这里的A with D with C with B
线性化为ADBC
,所以 new F().foo()
- 首先打印 "F"
,
- 然后是 super.foo()
即 "CBD"
。
顺便说一下,尝试将 A#foo()
更改为 return "A"
,然后你会看到在 E
中你覆盖了 A 的 foo
所以 "A"
没有出现在结果中,在F
中是"FCBDA"
.
所以让我们添加一些显示实例化顺序的行
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
因为你可以看到两种情况下的线性化不同!
当我们用一系列特征实例化 class 时,它与我们创建一个单独的 class 继承这些特征时不同。
所以根据线性化,调用顺序 foo
也不同。
当我们将 super.foo()
添加到 E
时就有点清楚了
根据我的理解,下面的代码是表达式的线性化
新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
我注意到如果我有一个像下面这样的 class F
class F extends A with D with C with B{
override def foo() = "F" + super.foo()
}
并做
new F().foo
它打印 "FCBD"
这对我来说似乎有点不一致,因为class F 的混合方式与表达式相同,但打印顺序不同
第一种情况new E with D with C with B
完美解释EDBC
,所以当你调用d.foo()
时,它
- 第一次调用
C#foo()
、 - 然后
B#foo()
、 - 然后
D#foo()
- 最后
E#foo()
。
如果你让E
成为一个特质,最后将其混合:val d = new D with C with B with E
,那么d.foo()
将return只是"E"
,因为特质E
是线性化中的 "last" 并且只是覆盖 foo
.
F
的情况不一样,因为你把foo
定义为"F" + super.foo()
,而super
这里的A with D with C with B
线性化为ADBC
,所以 new F().foo()
- 首先打印 "F"
,
- 然后是 super.foo()
即 "CBD"
。
顺便说一下,尝试将 A#foo()
更改为 return "A"
,然后你会看到在 E
中你覆盖了 A 的 foo
所以 "A"
没有出现在结果中,在F
中是"FCBDA"
.
所以让我们添加一些显示实例化顺序的行
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
因为你可以看到两种情况下的线性化不同! 当我们用一系列特征实例化 class 时,它与我们创建一个单独的 class 继承这些特征时不同。
所以根据线性化,调用顺序 foo
也不同。
当我们将 super.foo()
添加到 E