2009-12-03 58 views
90

我正在做一些案例類的匹配,並希望以相同的方式處理兩個案例。事情是這樣的:scala中匹配多個案例類

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

看起來你不關心字符串參數的值,並希望把B和C是相同的,所以:

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

如果你一定要,必須,必須提取參數,並在同一個代碼塊對待他們,你可以:

def matcher(l: Foo): String = { 
    l match { 
    case A() => "A" 
    case bOrC @ (B(_) | C(_)) => { 
     val s = bOrC.asInstanceOf[{def s: String}].s // ugly, ugly 
     "B(" + s + ")" 
    } 
    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 2009-12-03 07:01:21

+4

scala不允許「case A(aString)| cas​​e B(aString)=> println(aString)」嗎?似乎只要A和B的類型相同,就應該允許。你的最後一個例子似乎最好不要複製B和C的情況。 – 2011-11-09 01:18:34

+30

我會再給你一個。我認爲有'案例A(x)|'會很好B(x)=> println(x)'在'x'的類型被設置爲類型系統中無論A(x)和B(x)產生的上界的情況下都允許。 – 2011-11-10 17:24:55

4

那麼,它沒有任何意義,是嗎? B和C是互斥的,所以無論是sb還是sc都是綁定的,但是你不知道哪一個,所以你需要進一步的選擇邏輯來決定使用哪一個(假設它們綁定到一個Option [String],而不是一個字符串)。

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

或者這樣:所以有沒有收穫過這是

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

如果您不在乎B或C是否匹配,該怎麼辦?在以下代碼中說: 'args match {「 - x」,hostArg)=> (hostArg,true); case Array(hostArg,「-x」)=> (hostArg,true) }' 但是,我發現這不是常見情況,創建本地方法是另一種選擇。但是,如果替代方案很方便,那麼在選擇案例時就沒有多大意義。 實際上,在某些ML方言中,您有類似的功能,您仍然可以綁定變量,只要(IIRC)每個變量都綁定在兩個替代方案上的相同類型。 – Blaisorblade 2011-05-31 20:12:13

+0

你是對的。如果你只關心類型而不關心價值和類型,那麼基於類型的分離式匹配是有意義的。 – 2011-06-04 14:01:59

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

結構類型方法產生一個關於擦除的警告,目前我不知道如何消除。