2012-08-29 1 views
18

가능한 중복 :
Scala: forward references - why does this code compile?스칼라 앞으로 참조

object Omg { 

    class A 

    class B(val a: A) 

    private val b = new B(a) 

    private val a = new A 

    def main(args: Array[String]) { 
    println(b.a) 
    } 

} 

다음 코드 인쇄 "널 (null)". 자바. 무효 전방 참조 때문에 유사한 구조가 컴파일되지 않습니다. 질문은 왜 스칼라에서 잘 컴파일 되는가? 그것은 의도적으로 SLS에 설명되었거나 2.9.1의 버그입니까?

+1

이 그것이 발은 그 값을 변경할 수 있다는 것입니다에 대해 날 귀찮게 문제. 저를 슬프게합니다 :-( – thoredge

+0

조금 이상합니다. 많은 에러가 생길 수 있습니다. Java 동작에 의존하기 때문에 사용하기 전에 값을 초기화해야합니다. – jdevelop

+1

@jdevelop Java가 모두 catch하지 않습니다. 가능한 순방향 참조. –

답변

23

이것은 버그가 아니지만 스칼라를 배울 때 고전적인 오류입니다. 객체 Omg이 초기화되면 모든 값이 먼저 기본값 (이 경우 null)으로 설정되고 생성자 (즉, 객체 본문)가 실행됩니다.

object Omg { 

    class A 

    class B(val a: A) 

    private val b = new B(a) 

    private lazy val a = new A 

    def main(args: Array[String]) { 
    println(b.a) 
    } 
} 

a이 다음 필요에 따라 초기화됩니다

은 그냥 (이 경우 값 a) 선언이 앞으로 참조하고 앞에있는 lazy 키워드를 추가, 작동하게합니다.

이 구성은 빠르며 (값은 모든 응용 프로그램 런타임에 한 번만 초기화 됨) 스레드로부터 안전합니다.

+11

'lazy'를 추가하면 명령문을 잘못된 순서로 실행하고 있다는 것을 알게된다. 그러나 올바른 순서로 생각한다면, 아마도 "불필요한"게으른 것을 추가하지 않을 것입니다. : / – kornfridge

2

@paradigmatic 상태이므로 실제로 버그는 아닙니다. 그것은 선언 순서를 따르는 초기화 순서입니다. 이 경우 b이 선언/초기화 될 때 a은 null입니다.

private val b = new B(a)private lazy val b = new B(a)으로 변경하면 지연 문제를 사용하면 초기화가 지연되므로 문제가 해결됩니다. b의 첫 사용법.

이 동작은 SLS에 설명되어있을 가능성이 큽니다.

7

내가 이해하는 방식은 스칼라 클래스를 만드는 방법과 관련이있다. Java에서 위에서 정의 된 클래스는 변수를 인라인으로 초기화하는 것이며 a은 아직 정의되지 않았으므로 컴파일 할 수 없습니다. 그러나 스칼라에서 더는 (같은 시나리오에서 null을 생산한다) 자바에서이하는 것과 동일합니다 :

class Omg { 
    private B b = null; 
    private A a = null; 

    Omg(){ 
    b = new B(a); 
    a = new A(); 
    } 
} 

또는, 당신은 때까지 값을 설정 연기 할 것 게으른 b 당신의 선언을 만들 수 그것은 (어느 시점에 a가 설정되었는지) 호출된다.

6

문제가되는 경우 개발 중에 -Xcheckinit으로 컴파일하고 예외가 없어 질 때까지 반복하십시오.

Spec 5.1 템플릿 본문을 순서대로 실행합니다. 블럭에서 전방 참조를 위해 4.0의 시작.

Forward References - why does this code compile?