2012-10-22 2 views
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 

글쎄, 조금 이상합니다 ...하지만 이상하게 들립니다. 그때 나는 그래서 실제 lazy val을 시도 ... object의 애송이들이다 일부 게으른 평가로 갈 생각 :

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 특성이 매우 특별한 이유는 일반 값을 평가하지 않기 위해서입니까?

답변

9

응용 프로그램 확장 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; 
.... 

그래서 "I am null"값은 test 필드에만 할당됩니다. d elayedInit가 호출됩니다.

관련 문제