2010-07-28 2 views
5

나를 괴롭히는 스칼라 코드에서 오류가 발견되었습니다. 아래는 문제의 단순화 된 버전입니다.스칼라 추상 메소드는 서브 클래스가 val을 사용하여 구현할 때 수퍼 클래스에서 null입니다.

추상 클래스의 생성자에서 추상 메서드에 대한 몇 가지 주장을 확인하고 싶습니다. 따라서 하위 클래스의 객체가 만들어지면이 선언이 검사되어 모든 객체가 구현되었는지 확인합니다.

스칼라 코드 :

abstract class A { 
    def aval : String 
    assert(aval != null, "aval == null") 
    assert(aval == "B", "aval: "+aval) 
} 

class B extends A { 
    def aval = "B" 
} 

class C extends A { 
    val aval = "B" 
} 

object VariousScalaTests { 
    def main(args : Array[String]) : Unit = { 
     val b = new B 
     val c = new C 
    } 
} 

스칼라 오류 :

Exception in thread "main" java.lang.AssertionError: assertion failed: aval == null 
    at scala.Predef$.assert(Predef.scala:92) 
    at A.<init>(VariousScalaTests.scala:4) 
    at C.<init>(VariousScalaTests.scala:12) 
    at VariousScalaTests$.main(VariousScalaTests.scala:19) 
    at VariousScalaTests.main(VariousScalaTests.scala) 

그래서 그것은에 실패 서브 클래스는 그러나 "발"을 사용하여 추상 메소드를 구현하는 경우

그것은 잘못 마지막 줄의 코드 : "val c = new C". 클래스 B는 완벽하게 작동하지만 클래스 C는 완벽하게 작동하지 않습니다! 유일한 차이점은 C가 "val"을 사용하여 aval을 구현하고 "def"를 사용하여 B를 구현한다는 것입니다.

내 질문, 무엇보다도이 차이점은 무엇입니까? 나는 무슨 일이 일어나고 있는지 이해하지 못한다.

그리고 scala에서 두 경우 모두 원하는대로 작동하도록 만드는 방법이 있습니까? 아니면 내가 스칼라에서 원하는 것을 단언하는 더 우아한 방법을 놓치고 있는가?

답변

5

이 해당 자바 코드는 문제를 설명해야한다 : 당신이

val c = new C 

A 실행 전에 C의 생성자의 생성자와 _aval 필드를 실행하면

public abstract class A { 
    public String aval(); 
} 

public class B extends A { 
    public String aval() { 
     return "B"; 
    } 
} 

public class C extends A { 
    private String _aval; 

    public C() { 
     _aval = "B"; 
    } 

    public String aval() { 
     return _aval; 
    } 
} 

는 할당되지 않은 아직. 따라서 aval() 메서드는 null (_aval 필드의 초기 값)을 반환합니다. 그러나에서

val b = new B 

그런 문제가 없습니다. 일반적으로

, you should try to avoid calling virtual methods from a constructor.

And is there a way to make it work as I want in both cases in scala?

몇 가지 방법에 대한 this question 참조하십시오. 스칼라에서

+0

Java 코드가 잘 설명! 지금은 ... "이런 경우에는 생성자에서 가상 메서드를 호출하지 않는 것이 좋습니다"라고 매우 조언합니다. 확실히 자바 코드에서와 같이 스칼라에서 무엇이 진행되고 있는지 명확하게 알 수 있습니다. 내 특정 사례에서 하위 클래스를 우아하게 검사하기 위해 다른 방법을 검색합니다. 링크가 도움이 될 수 있습니다. 적어도이 오류의 수수께끼는 이제 사라졌습니다 ;-) –

6

당신은 서브 클래스의 발 슈퍼 생성자를 호출하기 전에 초기화 원인이 초기 정의를 기능을 사용할 수 있습니다

class C extends { 
    val aval = "B" 
} with A 
+0

이 기능을 초기화 전 필드라고합니다. 맞습니까? – missingfaktor

+0

확실하지 않습니다. scala lang spec 섹션 5.1.6에서는 "Early definitions"라고 부릅니다. – venechka

관련 문제