关于特质继承的困惑

时间:2016-06-10 01:12:51

标签: scala

我已在Scala中编写此代码

class MI {
    def identity : Int = {
        println("came inside MI") 
        1
    }
}

trait DMI extends MI {
    override def identity : Int = {
        println("came inside DMI")
        2 * super.identity
    }
}

trait TMI extends MI {
    override def identity : Int = {
        println("came inside TMI")
        3 * super.identity
    }
}

class Foo extends TMI with DMI {
    override def identity : Int = super[DMI].identity
}

val f = new Foo
f.identity

代码的输出是

came inside DMI
came inside TMI
came inside MI
res5: Int = 6

任何人都可以解释为什么电话会进入TMI?据我说,答案应该是2.

2 个答案:

答案 0 :(得分:2)

您正在使用可堆叠行为。当Scala遇到new时,它会使类线性化。此线性化决定在遇到super时将调用链中的哪个方法。对于您的示例,Foo的线性化将类似于:

Foo -> DMI -> TMI -> MI -> AnyRef -> Any

因此,如果在任何方法中遇到super,则将从右向左选择实现。在这种情况下,由于在super[DMI].identity的{​​{1}}方法中使用了identity

  • 首先它从Foo执行identity(因为您已明确使用DMI 不会使用线性化),它再次具有super[DMI]和 按线性化
  • 它从super.identity执行identityTMI再次super.identity 并按照线性化
  • identity
  • 执行MI

这就是为什么你得到6作为最终输出的原因。

注意如果您从super[TMI].identity内部调用Foo,结果将是3

有关线性化的更多详细信息,请参阅this链接。

答案 1 :(得分:1)

FOO的结构如下:

  1. TMI与DMI {Foo}

  2. 展开所有类型,直至到达任何

  3. (Any with with AnyRef with MI with TMI)with(Any with AnyRef with MI with DMI)with {Foo}

    1. 从左向右移动,删除所有重复项
    2. (任何带有带有TMI的MI的AnyRef)和带有{Foo}

      的(DMI)
      1. 以下是结果类型。现在从右侧开始并检查超级行为
      2. 的行为方式

        AnyRef with MI with TMI with DMI with {Foo}