2012-10-03 184 views
8

我有一個案例類像下面這樣:斯卡拉鴨打字模式匹配

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

我想匹配:

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

有合併的方式,3箱子成一個單一的情況下(無需向A,B,C添加中間父類)?我無法更改A,B,C或Exp的定義。某種:

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

這顯然是行不通的,也不做:

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

回答

11

雖然下面的「解決方案」是真的寫你已經擁有的只是用不同的方式,它可能會幫助如果您需要在多個地方使用相同的match,並且希望避免代碼重複。

以下的自定義不應用:

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

允許你寫

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

這樣,你並不需要在所有修改原來的類。我不知道有更好的方法來做到這一點,不涉及修改A/B/C類,但我渴望學習@ Stackoverflow;)