scala – 堆叠特征中super的含义取决于呼叫站点?

我无法用语言对此进行非常好的描述,所以,请看一下这个例子:

trait Base { def foo = "Base" }
trait One extends Base { override def foo = "One <: " + super.foo }
trait Two extends Base { override def foo = "Two <: " + super.foo }

new Base with One with Two {} foo

这打印:两个<:One&lt ;: Base,这是我所期待的.
现在,我正在尝试添加另一个级别,以便覆盖的特征不必显式调用super.像这样:

trait Base { def foo = "Base" }
trait Foo extends Base { def bar = foo + " <: " + super.foo }
trait One extends Foo { override def foo = "One" }
trait Two extends Foo { override def foo = "Two" }

new Foo with One with Two {} bar

这里,最后一行打印出两个&lt ;: Base

因此,在第一个例子中看起来像super表示One,而在最后一个示例中它跳过One并直接转到Base.

为什么会这样?不应该是一样的行为吗?

最佳答案 在第一种情况下,新的Base with One with Two {} foo(与新的One with two {} foo相同),“trait stack”非常明显. Two有一个foo,它调用超级(One)的foo,它调用超级(Base)的foo.

在第二种情况下,新的Foo与One with Two {} bar(与具有Two {} bar的新One相同),“trait stack”是Base-> Foo-> One-> Two.你打电话给酒吧,但是两个没有酒吧,一个没有酒吧. Foo有一个叫它super(Base)的foo的吧.

UPDATE

考虑@Dima提出的这个mod.

trait Base { def foo = "Base" }
trait Foo extends Base { def bar = foo + " <: " + super.foo }
trait One extends Foo { override def bar = super.bar
                        override def foo = "One" }
trait Two extends Foo { override def bar = super.bar
                        override def foo = "Two" }

new One with Two {} bar  // no Base or Foo needed

是的,这给出了与之前相同的输出:res0:String = Two<:Base 现在两个调用超级(One)的栏,它调用超级(Foo)的栏,调用其超级的foo(不是栏). 所有这些bar活动都与foo定义分开.两个从不调用它的超级foo,所以One.foo从未使用过,也不能成为输出的一部分. 一种不同的方法 考虑以下.

trait B { def id = "B" } // B for Base

trait V extends B { override def id = "V" }
trait W extends B { override def id = "W" }
trait X extends B { override def id = "X" }
trait Y extends B { override def id = "Y" }
trait Z extends B { override def id = "Z" }

trait R extends B { override def id = "R"; def mySup = super.id } // Required

现在尝试以多种不同的方式实例化它.

val r = new V with Y with W with R with X {} // B not needed
// or
val r = new W with R with Z with X with V {}
// or
val r = new R with Y with V with B with W {}
// or
val r = new Z with Y with X with W with R {}
// etc.

在每种情况下,r.id将是链中的最后一个特征,r.mySup将是R之前的特征(如果在R之前没有指定,则为B).

点赞