2009-12-03 71 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)) 
    } 
} 

结构类型方法产生一个关于擦除的警告,目前我不知道如何消除。