在加载扩展App的对象时scala会发生什么?

gil*_*och 5 scala lazy-evaluation

我在扩展的对象中遇到了一些bizzar行为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
Run Code Online (Sandbox Code Playgroud)

好吧,这有点奇怪......但它变得更加怪异.然后我认为vals object进入一些懒惰的评估...所以我尝试了一个真实的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?
Run Code Online (Sandbox Code Playgroud)

那么这里发生了什么?为什么常规val获得空值?
当我使用时,为什么这种行为会改变lazy val
这个App特质有什么特别之处,这使得常规价值得不到评估?

zve*_*vez 9

App扩展了DelayedInit特性.因此,所有语句和所有值定义都将移至delayedInit方法.Lazy val可以工作,因为它编译为方法.

例如,如果您反编译此类:

class TestApp extends App{
  val test = "I am null"
  lazy val testLazy ="I am a string"
}
Run Code Online (Sandbox Code Playgroud)

您将使用'懒惰方法'获得课程:

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;
} 
Run Code Online (Sandbox Code Playgroud)

和内部类中的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;
....
Run Code Online (Sandbox Code Playgroud)

因此,test只有在调用delayedInit时,才会将值"I is null"分配给字段.