首页 文章

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

提问于
浏览
5

我在扩展 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 中的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获得空值?
当我使用 lazy val 时,为什么这种行为会改变?
App 特性有什么特别之处,这使得常规值不被评估?

1 回答

  • 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方法 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;
    ....
    

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

相关问题