2012-10-03 4 views
8

ich einen Fall Klasse wie die haben folgende:Scala Ente eingeben Musterabgleich

// 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 

I übereinstimmen soll:

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) { ... } 

gibt es eine Möglichkeit zu fusionieren, dass drei Fälle in einem einzigen Fall (ohne eine übergeordnete Elternklasse zu A, B, C hinzuzufügen? Ich kann die Definition von A, B, C oder Exp nicht ändern. Eine Art:

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

die offensichtlich nicht funktioniert, genauso wenig wie:

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

Antwort

11

Während die folgende „Lösung“ ist eigentlich nur eine andere Art zu schreiben, was Sie bereits haben, könnte es helfen, wenn Sie denselben match an mehr als einer Stelle verwenden müssen und Code-Duplizierung vermeiden möchten.

Die folgende benutzerdefinierte Unapply:

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 
    } 
} 

Sie

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

diese Weise können Sie überhaupt die ursprünglichen Klassen zu ändern brauchen nicht zu schreiben. Ich bin mir nicht bewusst, eine bessere Möglichkeit, dies zu tun, ohne die A/B/C-Klassen zu ändern, aber ich bin gespannt auf @ Stackoverflow;)