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

时间:2012-10-22 10:16:32

标签: scala lazy-evaluation

我在扩展App的对象中遇到了一些bizzar行为。看看以下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中的val进行了一些懒惰的评估...所以我尝试了一个真正的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获得空值?
当我使用lazy val时,为什么这种行为会发生变化?  App特性有什么特别之处,使得常规值不被评估?

1 个答案:

答案 0 :(得分:9)

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

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

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

你将使用'懒惰方法'来上课:

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.body中的

和delayedInit方法:

 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;
....

只有在调用delayedInit时,才会将值“我为空”分配给test字段。