Scala可堆叠的特征

时间:2016-11-13 22:49:56

标签: scala 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

我注意到如果我有一个类F,如下所示

class F extends A with D with C with B{
      override def foo() = "F" + super.foo()
}

并做

new F().foo

打印“FCBD”

对我来说似乎有点不一致,因为F类与表达式的混合方式相同但打印顺序不同

2 个答案:

答案 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

时,这有点清楚