在 Scala 中匹配多个案例类
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1837754/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Match multiple cases classes in scala
提问by timdisney
I'm doing matching against some case classes and would like to handle two of the cases in the same way. Something like this:
我正在对某些案例类进行匹配,并希望以相同的方式处理其中的两个案例。像这样的东西:
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"
}
}
But when I do this I get the error:
但是当我这样做时,我收到错误:
(fragment of test.scala):10: error: illegal variable in pattern alternative
case B(sb) | C(sc) => "B"
I can get it working of I remove the parameters from the definition of B and C but how can I match with the params?
我可以让它工作,我从 B 和 C 的定义中删除参数,但我如何与参数匹配?
回答by Mitch Blevins
Looks like you don't care about the values of the String parameters, and want to treat B and C the same, so:
看起来您并不关心 String 参数的值,并且希望将 B 和 C 视为相同,因此:
def matcher(l: Foo): String = {
l match {
case A() => "A"
case B(_) | C(_) => "B"
case _ => "default"
}
}
If you must, must, must extract the parameter and treat them in the same code block, you could:
如果您必须,必须,必须提取参数并在同一代码块中处理它们,您可以:
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"
}
}
Though I feel it would be much cleaner to factor that out into a method:
尽管我觉得将其分解为一种方法会更清晰:
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"
}
}
回答by Don Mackenzie
There are a couple of ways that I can see to achieve what you are after, if you have some commonality between case classes. The first is to have the case classes extend a trait which declares the commonality, the second is to use a structural type which removes the need to extend your case classes.
如果案例类之间有一些共性,我可以通过几种方法来实现您的目标。第一个是让案例类扩展一个声明共性的特征,第二个是使用结构类型,它消除了扩展案例类的需要。
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))
}
}
The structural type method generates a warning about erasure which, at present I'm not sure how to eliminate.
结构类型方法会生成关于擦除的警告,目前我不确定如何消除。
回答by Randall Schulz
Well, it doesn't really make sense, does it? B and C are mutually exclusive, so either sb or sc get bound, but you don't know which, so you'd need further selection logic to decide which to use (given that they were bound to a Option[String], not a String). So there's nothing gained over this:
嗯,这真的没有意义,不是吗?B 和 C 是互斥的,所以 sb 或 sc 被绑定,但你不知道哪个,所以你需要进一步的选择逻辑来决定使用哪个(假设它们绑定到 Option[String],而不是一个字符串)。所以没有任何好处:
l match {
case A() => "A"
case B(sb) => "B(" + sb + ")"
case C(sc) => "C(" + sc + ")"
case _ => "default"
}
Or this:
或这个:
l match {
case A() => "A"
case _: B => "B"
case _: C => "C"
case _ => "default"
}

