【问题标题】:Weird initialisation when override val met DelayedInit in ScalaScala中覆盖val遇到DelayedInit时的奇怪初始化
【发布时间】:2013-07-18 16:58:33
【问题描述】:

以下代码的输出让我感到困惑。

代码

object Test1 {
  trait A {
    val s: String = "A"
    println(s"s = $s")
  }

  abstract class B extends A with DelayedInit {

    override def delayedInit(body: => Unit) = {
      println("B " + "1" * 80)
      body
      println("B " + "2" * 80)
    }
  }

  abstract class C extends A with DelayedInit {

    override val s: String = "C"

    override def delayedInit(body: => Unit) = {
      println("C " + "1" * 80)
      body
      println("C " + "2" * 80)
    }
  }

  def main {
    println("-- new B begin")
    new B {
      println("new B context")
    }
    println("-- new B end")

    println("-- new C begin")
    new C {
      println("new C context")
    }
    println("-- new C end")
  }
}

object Test2 {
  trait A {
    def s: String = "A"
    println(s"s = $s")
  }

  abstract class B extends A with DelayedInit {

    override def delayedInit(body: => Unit) = {
      println("B " + "1" * 80)
      body
      println("B " + "2" * 80)
    }
  }

  abstract class C extends A with DelayedInit {

    override def s: String = "C"

    override def delayedInit(body: => Unit) = {
      println("C " + "1" * 80)
      body
      println("C " + "2" * 80)
    }
  }

  def main {
    println("-- new B begin")
    new B {
      println("new B context")
    }
    println("-- new B end")

    println("-- new C begin")
    new C {
      println("new C context")
    }
    println("-- new C end")
  }
}

println("Test1")
Test1.main
println("Test2")
Test2.main

输出

Test1
-- new B begin
s = A
B 11111111111111111111111111111111111111111111111111111111111111111111111111111111
new B context
B 22222222222222222222222222222222222222222222222222222222222222222222222222222222
-- new B end
-- new C begin
s = null
C 11111111111111111111111111111111111111111111111111111111111111111111111111111111
C 22222222222222222222222222222222222222222222222222222222222222222222222222222222
C 11111111111111111111111111111111111111111111111111111111111111111111111111111111
new C context
C 22222222222222222222222222222222222222222222222222222222222222222222222222222222
-- new C end
Test2
-- new B begin
s = A
B 11111111111111111111111111111111111111111111111111111111111111111111111111111111
new B context
B 22222222222222222222222222222222222222222222222222222222222222222222222222222222
-- new B end
-- new C begin
s = C
C 11111111111111111111111111111111111111111111111111111111111111111111111111111111
new C context
C 22222222222222222222222222222222222222222222222222222222222222222222222222222222
-- new C end

尝试了 scala 2.10.2 和 2.11.0-M3。

在我的理解中,Test1 应该和 Test2 一样。这里有两个问题:

  • 为什么 DelayedInit 在 Test1.C 中被调用了两次?类层次结构中没有其他类继承该特征
  • 为什么要在 Test1.C 中使用 s == null?

【问题讨论】:

    标签: scala init


    【解决方案1】:

    为什么DelayedInit 在Test1.C 中被调用了两次?类层次结构中没有其他类继承该特征

    这看起来像一个错误,请尝试将其报告给 Scala JIRA。


    为什么在Test1.C 中有s == null?

    我会说这是因为val 在

    override val s: String = "C"
    

    由一个内部变量支持,该变量在C 的初始化期间被初始化。而且因为DelayedInit没有捕获traits,所以A的初始化在delayedInit之前执行,也就是在C和val s被初始化之前。

    (如果有人为这些类发布反编译的 Java 代码会很有趣。)

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-22
    • 2012-02-23
    • 1970-01-01
    • 2012-11-10
    • 2014-10-12
    相关资源
    最近更新 更多