2011-11-05 2 views
2

스칼라에서 상속 및 하한 문제가 있습니다. 내가 예와 함께 설명하려고합니다 : 을 나는 같은 서명 클래스 사람이 : 나는 또한 아이 클래스 노동자를 만들었습니다스칼라 상속 및 하한 문제

def doSomething[P<%Person](persons :List[P]) { 
} 

, 그의 방법 해봐요은 다음과 같습니다

override def doSomething(persons: List[Worker]) { 
} 

그러나 Worker.doSomething()이 아무 것도 재정의하지 않는다는 오류가 발생합니다.

답변

3

이 방법으로 상속받을 수 없습니다. Liskov Substitution Principle을 위반합니다. 왜 그런지 보여 드리겠습니다. 당신이이 클래스를 컴파일 할 수 있다고 가정 :

class Person { 
    def doSomething[P<%Person](persons :List[P]) { 
    } 
} 

class Worker extends Person { 
    override def doSomething(persons: List[Worker]) { 
    } 
} 

자,이 간단한 프로그램이 실패 : p2 이후

val p1: Person = new Worker 
val p2: Person = new Person 
p1.doSomething(List(p2)) 

Worker 아니라, 그 호출이 유효하지 않습니다. 그러나 p1Person이므로 해당 호출이 유효합니다! 이 모순은 당신이 제안한 오버라이드의 결과입니다.

하지만 그보다 더 나쁩니다! 이 ALSO이 작동하지 않습니다 :

p1.doSomething[Worker](List(p1)) 

을 지금, 그것은 노동자의 목록을 통과하더라도, p1에 의해 예상대로 doSomethingWorker에이 형식 매개 변수을 기대하지 않기 때문에 실패합니다. 그러나 메서드 doSomethingPerson 인 경우 형식 매개 변수를 전달해야한다고 선언했습니다. 다시, 모순은 당신이 제안한 오버라이드의 결과입니다.

상속이 인 것을 기억하십시오. 관계는입니다. WorkerPerson 인 경우 Person과 같이 Person과 같이과 같이 행동해야합니다. 그것이 당신이 만들고자하는 관계가 아니라면, 상속을 사용하지 마십시오.

4

일반 메서드는 사람의 하위 클래스 인 을 전달하는 한 작동하기 때문에 특정 메서드는 제네릭 메서드를 재정의 할 수 없습니다 (특정 클래스는 일반 클래스를 확장 할 수 있지만). 구체적인 방법은 하위 클래스를 취하지 않습니다. 그것은 단지 Worker 걸릴 것입니다.

+0

답해 주셔서 감사합니다. 그러나 Worker.doSomething() 메서드에서 일반 Person 클래스가 아닌 Worker 클래스의 특성에 액세스하고 싶습니다. 캐스팅하지 않고 이러한 속성에 액세스 할 수있는 방법이 있습니까? – user485659

+0

@ user485659 - 할 일을 조금 더 설명해 주시겠습니까? 내 답변 하이라이트로 클래스를 재정의하는 것은 논리적으로 올바르지 않습니다. 캐스트는 실패 할 수도 있습니다 (즉, Person과 작동하는 일반 코드에서 List [Worker]가 인수로만 호출된다는 보장이 없음). –

+0

@ user485659 다른 질문이 있으면 다른 질문으로 질문하십시오. 그러나 간단히 말해서, 당신은 어떤 물건에 대해서 결코 묻지 말아야합니다. 대신에 무엇을해야 할지를 말해야합니다. 어떤 경우에는 메커니즘 자체를 처리합니다. 그러나 _pattern matching_을 사용하여 우수 사례를 유지하지 않아도됩니다. –