2

次のコードの出力は私を混乱させます。

コード

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 と同じでなければなりません。ここに2つの質問があります:

  • Test1.C で DelayedInit が 2 回呼び出されたのはなぜですか? クラス階層内に他のクラスがトレイトを継承していない
  • なぜs == nullTest1.C で?
4

1 に答える 1

1

Test1.C で DelayedInit が 2 回呼び出されたのはなぜですか? クラス階層内に他のクラスがトレイトを継承していない

これはバグのようです。Scala JIRA に報告してみてください。


なぜs == nullTest1.C

私はそれが中だからだと思いvalます

override val s: String = "C"

は内部変数によってサポートされており、この変数は の初期化中に初期化されますC。また、DelayedInitは をキャプチャしないためtrait、 の初期化は のA前に実行されます。delayedInitつまり、Cval sが初期化される前です。

(誰かがクラスの逆コンパイルされた Java コードを投稿すると興味深いでしょう。)

于 2013-07-18T08:58:33.110 に答える