【问题标题】:Scala mixin sets overridden variable to nullScala mixin 将覆盖的变量设置为 null
【发布时间】:2014-09-10 06:21:36
【问题描述】:

我有以下情况:

class A {
  val text = "Test"
  //some initialization things using text. here represented by println
  println(text)
}

现在我想为该类编写单元测试,因此为此目的更改 text 的值。

trait Test extends A {
  override val text = "Hello"
}

class B extends A with Test 

问题是,现在如果我创建B 的实例,文本的值会按预期设置为"Hello",但A 中的所有初始化步骤都会为null 得到null 的值@

See this fiddle for demo

我的问题是为什么变量null 是原始class A 中的语句?我想拥有旧的价值似乎比突然没有价值更合乎逻辑。

【问题讨论】:

    标签: scala mixins


    【解决方案1】:

    当你编写val text = ... 时,编译器会生成一个私有的final 字段(我们称之为_text)和一个访问它的方法。这发生在AB 中。 B的构造函数首先调用A的构造函数,但它使用的text方法是B的;所以它访问了尚未初始化的B._text

    作为@DennisTraub 答案中def 的替代方案,您还可以使用lazy val 来避免重新计算答案(不过,def 在这种情况下更好)。在我看来,您通常不应覆盖 vals 以避免此类问题。

    【讨论】:

    • 是的,我也开始意识到,如果在某些情况下值可能需要不同,那么我作为 hack 覆盖的val 可能是这不是实现它的正确方法。
    【解决方案2】:

    不幸的是,我不知道它为什么会这样,但我通过使用 def 而不是 val 解决了手头的问题:

    class A {
      def text = "Test"
      println(text)
    }
    
    trait Mix extends A {
      override def text = "Hello"
    }
    

    【讨论】:

    • 这是一个不错且简单的解决方法。我没有回答这个问题,因为你的回答绝对有帮助,但没有回答我的问题“为什么”它会这样。 +1 你,因为我相信你已经帮助人们处理这种问题,在未来绊倒这个线程。
    猜你喜欢
    • 2012-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多