2009-12-03 3 views
90

일부 사례 클래스와의 비교를 수행하고 있으며 두 가지 사례를 동일한 방식으로 처리하려고합니다. 이런 식으로 뭔가 :여러 사례 클래스를 스칼라로 일치

abstract class Foo 
case class A extends Foo 
case class B(s:String) extends Foo 
case class C(s:String) extends Foo 


def matcher(l: Foo): String = { 
    l match { 
    case A() => "A" 
    case B(sb) | C(sc) => "B" 
    case _ => "default" 
    } 
} 

하지만이 작업을 수행 할 때 오류 얻을 :

(fragment of test.scala):10: error: illegal variable in pattern alternative 
    case B(sb) | C(sc) => "B" 

나는 그것이 내가의 작업을 진행 B와 C의 정의에서 매개 변수를 제거하지만 난 어떻게 일치시킬 수 있습니다 매개 변수는?

답변

123

이 보이는 그래서, 그래서이를 통해 얻은 아무것도 없다 :

def matcher(l: Foo): String = { 
    l match { 
    case A() => "A" 
    case B(_) | C(_) => "B" 
    case _ => "default" 
    } 
} 

당신이해야하는 경우, 매개 변수를 추출하고 동일한 코드 블록을 취급해야한다, 그럴 수 :

나는이 방법으로 그을 고려하는 것이 훨씬 청소기 될 것이다 느낌이 있지만

:

def doB(s: String) = { "B(" + s + ")" } 

def matcher(l: Foo): String = { 
    l match { 
    case A() => "A" 
    case B(s) => doB(s) 
    case C(s) => doB(s) 
    case _ => "default" 
    } 
} 
+0

나의 예는 그것을 보여주지 않지만 나는 그 매개를 필요로하고있다. 나는 단지 물건을 사용해야 할 것 같은데. 감사! – timdisney

+4

scala가 "case A (aString) | case B (aString) => println (aString)"을 허용하지 않는 이유가 있습니까? aString의 유형이 A와 B 모두에 대해 동일 할 때처럼 보입니다. 허용되어야합니다. 마지막 사례는 B와 C 사례를 복제하지 않는 것이 더 나을 것 같습니다. –

+30

나는 너를 하나 더 가야겠다. 나는'case A (x) |를 갖는 것이 좋을 것이라고 생각한다. B (x) => println (x)'A (x)와 B (x)가 생성하는 타입 시스템에서'x'의 타입이 상한으로 설정되는 곳에서 허용 될 수 있습니다. –

4

음, 실제로 이해가되지 않습니까? B와 C는 상호 배타적이므로 sb 또는 sc가 바인딩되지만 어느 것을 모를 것인지를 결정하기 위해 추가 선택 논리가 필요합니다 (Option [String]에 바인드 된 경우). String).

l match { 
    case A() => "A" 
    case B(sb) => "B(" + sb + ")" 
    case C(sc) => "C(" + sc + ")" 
    case _ => "default" 
    } 

또는이 : 당신이 동일한 문자열 매개 변수의 값을 걱정하고, B를 치료하고 싶은 C없는 것

l match { 
    case A() => "A" 
    case _: B => "B" 
    case _: C => "C" 
    case _ => "default" 
    } 
+0

B 또는 C가 일치하는지 상관하지 않는 경우 어떻게해야합니까? 다음 코드를 입력하십시오 : args match { case 배열 ("- x", hostArg) => (hostArg, true); case 배열 (hostArg, "-x") => (hostArg, true) } ' 그러나 일반적인 경우는 아니며 로컬 메소드를 만드는 것이 대안입니다. 그러나 대안이 편리하다면, 대안을 갖는 데는 거의 요지가 없습니다. 사실, 일부 ML 언어에서는 유사한 기능을 가지고 있으며 각 변수가 두 가지 대안 모두에서 동일한 유형으로 바인딩되는만큼 (IIRC) 길게 변수를 바인딩 할 수 있습니다. – Blaisorblade

+0

정확합니다. 값과 유형이 아닌 유형에만 관심이 있고 어떤 유형이 제시되는지는 분리 유형 기반 일치가 의미 있고 사용 가능합니다. –

8

난 당신이 몇 가지 공통점 사이에있는 경우, 이후에 무슨 달성하기 위해 볼 수있는 몇 가지 방법이 있습니다 사례 클래스. 첫 번째는 사례 클래스가 공통성을 선언하는 특성을 확장하도록하는 것이고 두 번째는 사례 클래스를 확장 할 필요를 제거하는 구조적 형식을 사용하는 것입니다.

object MuliCase { 
    abstract class Foo 
    case object A extends Foo 

    trait SupportsS {val s: String} 

    type Stype = Foo {val s: String} 

    case class B(s:String) extends Foo 
    case class C(s:String) extends Foo 

    case class D(s:String) extends Foo with SupportsS 
    case class E(s:String) extends Foo with SupportsS 

    def matcher1(l: Foo): String = { 
    l match { 
     case A  => "A" 
     case s: Stype => println(s.s); "B" 
     case _  => "default" 
    } 
    } 

    def matcher2(l: Foo): String = { 
    l match { 
     case A   => "A" 
     case s: SupportsS => println(s.s); "B" 
     case _   => "default" 
    } 
    } 

    def main(args: Array[String]) { 
    val a = A 
    val b = B("B's s value") 
    val c = C("C's s value") 

    println(matcher1(a)) 
    println(matcher1(b)) 
    println(matcher1(c)) 

    val d = D("D's s value") 
    val e = E("E's s value") 

    println(matcher2(d)) 
    println(matcher2(e)) 
    } 
} 

구조적 유형의 방법은 현재 내가 제거하는 방법을 잘 모르겠어요, 삭제에 대한 경고를 생성합니다.

관련 문제