为什么val和def在不同的时间实现抽象方法?

时间:2014-01-03 23:43:11

标签: scala traits

我正在使用scala并做了类似的事情:

trait Foo { val a: String }
trait Foo2 extends Foo { val a = "foo" }
trait Bar extends Foo { val b = a + "-bar" }
object Bar2 extends Bar with Foo2

我预计Bar2.b将是“foo-bar”,但它最终会成为“null-bar”。 Bar2.a正如预期的那样“foo”。

如果我从val变为def,那么'a'的定义就像这样:

trait Foo { def a: String }
trait Foo2 extends Foo { val a = "foo" }
trait Bar extends Foo { val b = a + "-bar" }
object Bar2 extends Bar with Foo2

Bar2.b实际上是“foo-bar”。

在示例2中,在评估val'b'之前,Foo2中用于实现Foo中的抽象的def'a'被放入Bar2的定义中。在示例1中,在Bar / Bar2中定义了val'b'之后,来自Foo2的val'a'覆盖了来自Foo的val'a'。

为什么会这样?为什么val和def在不同的时间实现抽象方法?

2 个答案:

答案 0 :(得分:4)

您始终希望在特征中使用deflazy val(而不仅仅是val),以避免您发现的尴尬行为。

至于为什么要获得Scala在JVM中实现的低级细节,请查看Josh Suereth在Scala Days 2012中的精彩演讲"Binary Resilience"

答案 1 :(得分:3)

这是因为背后有Java。初始化(非抽象)val被转换为具有私有字段的公共getter,并且它们按特定顺序初始化。抽象的vals只是吸气剂。检查Java文档。您还可以看到Scala的早期初始化器功能,以找到更好的解决方案: In Scala, what is an "early initializer"?

还有混合的顺序。这应该会给你正确的结果:

object Bar2 extends Foo2 with Bar