2017-05-12 10 views
1

나는이 코드가 작동하는 이유에 대해 궁금하고 스칼라를 사용하고있다.스칼라에서 부모 특성이 자식 클래스에 구현 된 메서드를 호출 할 수 있습니까?

trait Base { 
    def foo(x: Int): Int 
} 

trait A extends Base { 
    def fooA(x: Int): Int = { 
    foo(x) 
    } 
} 

class Impl extends Base with A { 
    override def foo(x: Int): Int = x 
} 

val a = new Impl 
a.fooA(10) 

a.fooA(10)의 결과 방법 fooAImpl는 클래스 구현 foo 방법을 사용하고, 형질 A 그러나 10
이다.
또한 Impl 클래스는 클래스 A (Impl 선언의 with A)을 확장합니다.

원형이 아닙니까?
어떻게 가능합니까?

감사합니다.

답변

2

는 모든 체크 아웃. Base은 누구든지 확장하여 foo에 대한 구현을 요구하며 이는 Impl이 수행합니다. 특성 A은 으로 확장되므로 foo을 사용할 수 있습니다. 모든 것이 분명하다.

그러나 혼란스러워합니다. 나는 그것을 원형이라고 부르지 않을 것이다. (Impl에서) 초기화되기 전에 뭔가 (에 foo)를 사용하는 것과 같습니다. 이유는이 작품은 def을 사용했기 때문입니다. 컴파일러는 나중에이 값을 사용할 수 있음을 알고 있습니다. 컴파일 프로세스의 나머지 부분에서이 값을 찾지 못하면 중단 될 것이고 단지 "그것이 호출 될 때 사용할 수 있습니다. 편집은 성공적입니다.) 그리고 그것은 def입니다. 이는 그때 그곳을 계산할 것임을 의미합니다. 그래서 지금은 할 필요가 없습니다. " lazy val이 같은 효과가 있습니다

trait Base { 
    val foo: Int 
} 

trait A extends Base { 
    val fooA: Int = foo 
} 

class Impl extends Base with A { 
    override val foo: Int = 42 
} 

val a = new Impl 
println(a.fooA) // prints 0 although we wanted 42 

하는 것으로 : 당신이 val 사용하는 경우

그러나 foo 그래서 당신은 Interegers 0입니다 초기 값을 얻을 것이다 A에 그 시점에서 을 초기화됩니다 def (게으 름으로 계산되었으므로 첫 번째 사용 시점에서 한 번만 계산 됨) 위의 코드를 override lazy val foo: Int = 42으로 수정하면 42도 인쇄됩니다.

2

foo는 특성에서 정의되어 impl에서 호출되고 구현 될 수 있도록 정의됩니다. 그것이 어디서부터 불려지는지는 정말로 중요하지 않습니다.

호출은 다음과 같이 진행됩니다. -> call fooA. 그것은 impl에서 상속받은 A에서만 정의됩니다. fooA는 foo를 호출합니다. foo가 특성에 정의되고 구현이 impl에 나타납니다. 이것은 원형이 아니라 가장 기본적인 사용법입니다.

하나 이상의 구현이 있다면 (예를 들어 특성 (A)에) 다음 순서는 선형화 기반으로 할 것 (https://stackoverflow.com/a/34243727/1547734 참조)보기의 편집 점에서