2011-06-13 7 views
9

에 포괄 성 확인을 보존 추출기와 케이스 클래스 상속 교체 이 같은 경기 블록 :I는 정점의 여러 가지 유형이 경우에 클래스를 사용하여 구현 그래프와 같은 구조를 나타내는 간단한 클래스 계층이 스칼라

def test (x: Node) = x match { 
    case _ : Arc => "got arc" 
    case _ : Vertex => "got vertex" 
} 

또는이 같은 :

def test (x: Node) = x match { 
    case _ : Arc => "got arc" 
    case c : Vertex => c match { 
    case _ : VertexType1(a) => "got type 1 vertex " + a 
    case _ : VertexType2(a) => "got type 2 vertex " + a 
    } 
} 

이 구현에는 다음과 같은 속성이 있습니다.

1) 특정 정점 유형 간에는 아니지만 정점 유형을 구별하는 블록과 일치하는 호와 정점을 구별하는 일치 블록을 작성할 수 있습니다.

2) 정점 유형별 및 비 정점 유형별 일치 블록 모두에서 패턴 일치의 완전성이 검사됩니다.

그러나 사례 클래스의 상속은 권장되지 않으며 컴파일러는 잎이 아닌 노드에서의 일치를 지원하기 위해 대신 추출기를 사용하는 것이 좋습니다 (예 : 위 예제에서는 호와 정점을 구별하지만 꼭지점 유형간에 구분하지 않음) .

질문 : 케이스 클래스 상속을 사용하지 않고 유사한 클래스 계층 구조를 구현할 수 있습니까? 그렇지만 위에 표시된 사용 사례 둘 다에서 컴파일러가 수행 한 패턴 완전성 검사는 여전히 있습니까?

EDIT : 일치 유형이 유형에만 적용되지 않도록 VertexType 클래스에 생성자 매개 변수를 추가했습니다.

sealed trait Node 

sealed abstract class Vertex extends Node 
class Arc extends Node 

class VertexType1 (val a:Int) extends Vertex 
class VertexType2 (val b:Int) extends Vertex 

object VertexType1 { 
    def unapply (x : VertexType1) : Some[Int] = Some(x.a) 
} 

object VertexType2 { 
    def unapply (x : VertexType2) : Some[Int] = Some(x.b) 
} 

그리고 테스트 코드 :

def test (x: Node) = x match { 
    case _ : Arc => "got arc" 
    case v : Vertex => v match { 
    case VertexType1(a) => "got vertex type 1 " + a 
    } 
} 

내가 두 번째 블록이 아닌 철저한 경기에 대한 경고를 기대 VertexType2은 (다음과 같은 경우 클래스없는

나의 현재 구현은 결코 일치하지 않음).

2.9.0-RC3 이전의 스칼라 컴파일러는 실제로 볼 수는 있지만 RC3 (2.9.0 및 2.9.0-1 포함)로 시작하는 버전은 그렇지 않다는 경고를 생성합니다. 다소 혼란 스럽습니다.

+1

완전성을 위해 : 이것은 스칼라 2.10에서 수정되었습니다. (Scala 2.9.x에서 회귀가있었습니다.) – gourlaysama

답변

0

scala-lang.org에서 인용 : 패턴 매치의 선택기가 봉인 된 클래스의 인스턴스 인 경우

, 패턴 매칭의 컴파일의 주어진 것으로 진단 경고를 방출 할 패턴이 철저하지는 않습니다. 즉, 런타임에 MatchErroring이 발생할 가능성이 있습니다.

2

추출기는 스칼라의 케이스 클래스와 같은 패턴 일치에 사용할 수 있지만 대소 문자 수정자를 사용할 때 얻을 수있는 다른 표준 구현은 없습니다. 그러나 이러한 여분의 구현 (특히 equals의 구현)은 케이스 클래스 상속을 위험하게 만들고 더 이상 사용되지 않게됩니다.

그러나 봉인 된 클래스는 직각 피쳐이므로 케이스 클래스 또는 추출기가 있는지 여부에 관계없이 사용할 수 있습니다. 추출기를 사용하면 표준 구현을 즉석에서 가져올 수 없으므로 추출기의 상속을 가질 수 있습니다. 이는 단순히 적용되지 않는 및/또는 unapplySeq 메서드가있는 일반 클래스입니다.

예제에서 수행 한 것을 유형에 대한 패턴 일치라고합니다. 이 작업을 수행하기 만하면 케이스 클래스에 추출기가 필요하지 않습니다. 당신은 당신이 원하는 모든 수업과 함께 할 수 있습니다. 따라서 case 수정자를 간단히 제거 할 수 있습니다.

결론적으로, 패턴의 철저한 성격은 봉인 된 클래스 히라시 (hirachies)에 의해 달성됩니다. 패턴 매칭은 추출기와 자주 사용되는 기능의 표준 구현이 매력적인 추출기 인 경우의 추출기 및 사례 클래스에 의해 수행됩니다. 도움이 되었기를 바랍니다.

+1

좋은 답변이지만 많은 오타가 있으면 다시 한 번 살펴 보시기 바랍니다. 감사! –

+0

이 답변을 주셔서 대단히 감사합니다. 케이스 모디파이어와는 반대로 봉인 된 계층 구조를 통해 완성 된 것을 알지 못했습니다. 그러나 패턴 일치를 유형을 넘어서 확장하면 (원래의 질문에이 수정 사항을 추가했습니다) 컴파일러 버전에 따라 예기치 않은 동작이 계속 발생합니다. ( –

2

일반적으로 이것은 수행 할 수 없습니다.

봉인 된 클래스는 scalac이 가능한 일치 수를 컴파일 타임에 알고 있기 때문에 특수한 경우 (말장난 없음)입니다.

그러나 추출기를 사용하면 임의의 코드를 실행할 수 있으므로 중단 가능한 문제가 발생하기 때문에 모든 경우에 컴파일러가 모든 경우를 확인할 수 있도록 모든 경우에 컴파일러가 보증 할 방법이 없습니다. 유형의 일부 값은 8의 배수가 아닌 숫자를 처리하지 못하기 때문에

def test(foo: Int) { 
    foo match { 
    case IsMultipleOf8(n) => printf("%d was odd\n", n) 
    } 
} 

이것은 철저한 아니라, 컴파일러는 (모든 Int 년대에 추출기를 실행하지 않고) 추론 할 수 없습니다 고려 Int은 8의 배수입니다.

+1

물론 일반적인 경우입니다. 그러나이 예제에서는 추출기 개체가 반환 값의 형식이 Some [Int]이고 Boolean 또는 Option이 아니기 때문에 항상 결과를 반환하므로 일치하지 않을 수 있습니다 (즉, 결국 적용되지 않은 메서드가 컴파일러는 (Node 타입의) 매치되는 값을 내재적으로 캐스팅 할 수 있다는 것에 유의해야한다. 추출기에서 허용하는 구체적인 유형이므로 계층 구조를 인식합니다. –