2012-10-03 12 views
8

Mam klasy takim wypadku następuje:Scala kaczka wpisując wzorzec dopasowania

// parent class 
sealed abstract class Exp() 

// the case classes I want to match have compatible constructors 
case class A (a : Exp, b : Exp) extends Exp 
case class B (a : Exp, b : Exp) extends Exp 
case class C (a : Exp, b : Exp) extends Exp 

// there are other case classes extending Exp that have incompatible constructor, e.g. 
//  case class D (a : Exp) extends Exp 
//  case class E() extends Exp 
// I don't want to match them 

Chcę dopasować:

var n : Exp = ... 
n match { 
    ... 
    case e @ A (a, b) => 
     foo(e, a) 
     foo(e, b) 
    case e @ B (a, b) => 
     foo(e, a) 
     foo(e, b) 
    case e @ C (a, b) => 
     foo(e, a) 
     foo(e, b) 
    ... 
} 

def foo(e : Exp, abc : Exp) { ... } 

czy istnieje sposób, aby scalić, że trzy przypadki, w pojedynczym przypadku (bez dodawania pośredniej klasy rodzicielskiej do A, B, C)? Nie mogę zmienić definicji A, B, C lub Exp. Jakiś:

var n : Exp = ... 
n match { 
    ... 
    case e @ (A | B | C) (a, b) => // invalid syntax 
     foo(e, a) 
     foo(e, b) 
    ... 
} 

co oczywiście nie działa, ani zrobić:

var n : Exp = ... 
n match { 
    ... 
    case e @ (A (a, b) | B (a, b) | C (a, b)) => // type error 
     foo(e, a) 
     foo(e, b) 
    ... 
} 

Odpowiedz

11

Chociaż po „rozwiązanie” jest tak naprawdę inny sposób pisania, co już masz, to może pomóc jeśli potrzebujesz użyć tego samego match w więcej niż jednym miejscu i chcesz uniknąć duplikowania kodu.

Poniższy zwyczaj Wycofywanie:

object ExpABC { 
    def unapply(e:Exp):Option[(Int, Int)] = e match { 
     case A(a, b) => Some(a, b) 
     case B(a, b) => Some(a, b) 
     case C(a, b) => Some(a, b) 
     case _ => None 
    } 
} 

pozwala pisać

n match { 
    case e @ ExpABC(a, b) => 
     println(e) 
     println(a) 
     println(b) 
} 

W ten sposób nie trzeba modyfikować oryginalne zajęcia w ogóle. Nie jestem świadomy lepszego sposobu, aby to zrobić, który nie wymaga modyfikacji klas A/B/C, ale jestem chętny do nauki @ Stackoverflow;)