5

を拡張するオブジェクトで、やや奇妙な動作に遭遇しましたApp。次のREPLコマンドを見てください。

scala> object A extends App {val x = "I am null"}
defined module A

scala> object B {val x = "I am a string"}
defined module B

scala> A.x
res0: java.lang.String = null

scala> B.x
res1: java.lang.String = I am a string

まあ、これは少し奇妙です...しかし、それはより奇妙になります。objectそれから私はいくつかの怠惰な評価に入るvalsを考えました...それで私は本物を試しましたlazy val

scala> object C extends App {lazy val x = "What am I?"}
defined module C

scala> C.x
res2: java.lang.String = What am I?

では、ここで何が起こっているのでしょうか。通常のvalがnull値を取得するのはなぜですか?
使用するとこの動作が変わるのはなぜlazy valですか?そして、通常の値が評価されないようにする特性
の特別な点は何ですか?App

4

1 に答える 1

9

アプリはDelayedInitトレイトを拡張します。したがって、すべてのステートメントとすべての値の定義はメソッドに移動されdelayedInitます。レイジーvalは、メソッドにコンパイルされるため機能します。

たとえば、このクラスを逆コンパイルする場合:

class TestApp extends App{
  val test = "I am null"
  lazy val testLazy ="I am a string"
}

'lazyメソッド'でクラスを取得します:

public String testLazy()
{
    if((bitmap$0 & 1) == 0)
        synchronized(this)
        {
            if((bitmap$0 & 1) == 0)
            {
                testLazy = "I am a string";
                bitmap$0 = bitmap$0 | 1;
            }
            BoxedUnit _tmp = BoxedUnit.UNIT;
        }
    return testLazy;
} 

内部クラスのdelayedInitメソッドdelayedInit.body

 public final class delayedInit.body extends AbstractFunction0
        implements ScalaObject
    {

        public final Object apply()
        {
            $outer.test_$eq("I am null");
            return BoxedUnit.UNIT;
        }

        private final TestApp $outer;
....

testしたがって、delayedInitが呼び出された場合にのみ、値「Iamnull」がフィールドに割り当てられます。

于 2012-10-22T10:27:01.273 に答える