匹配scala中的多个案例类

tim*_*ney 99 scala pattern-matching

我正在对一些案例类进行匹配,并希望以相同的方式处理其中两个案例.像这样的东西:

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"
  }
}
Run Code Online (Sandbox Code Playgroud)

但是当我这样做时,我得到错误:

(fragment of test.scala):10: error: illegal variable in pattern alternative
    case B(sb) | C(sc) => "B"
Run Code Online (Sandbox Code Playgroud)

我可以使用它从B和C的定义中删除参数,但我怎样才能与params匹配?

Mit*_*ins 143

看起来你不关心String参数的值,并且想要对待B和C相同,所以:

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

如果必须,必须,必须提取参数并在同一代码块中处理它们,您可以:

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"
  }
}
Run Code Online (Sandbox Code Playgroud)

虽然我觉得把它分解成一种方法会更清晰:

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"
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我再告诉你一件事.我认为有一个案例A(x)|会很好 B(x)=> println(x)`允许将`x`的类型设置为A(x)和B(x)产生的类型系统的上限. (34认同)
  • 有没有理由scala不允许"案例A(aString)|案例B(aString)=> println(aString)"?似乎只要aString的类型对A和B都相同,就应该允许它.你的最后一个例子似乎最好不要复制B和C案例. (4认同)
  • 对于那些想知道 @ 符号在那里做什么的人:http://www.scala-lang.org/files/archive/spec/2.11/08-pattern-matching.html (2认同)

Don*_*zie 9

如果你在案例类之间有一些共性,我可以通过几种方式来实现你所追求的目标.第一个是让case类扩展一个声明共性的特性,第二个是使用一个结构类型,它不需要扩展你的case类.

 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))
   }
 }
Run Code Online (Sandbox Code Playgroud)

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


Ran*_*ulz 6

好吧,这真的没有道理,对吗?B和C是互斥的,因此sb或sc被绑定,但是您不知道哪个,因此您需要进一步的选择逻辑来决定使用哪个(假设它们绑定到Option [String],而不是字符串)。因此,没有任何收获:

  l match {
    case A() => "A"
    case B(sb) => "B(" + sb + ")"
    case C(sc) => "C(" + sc + ")"
    case _ => "default"
  }
Run Code Online (Sandbox Code Playgroud)

或这个:

  l match {
    case A() => "A"
    case _: B => "B"
    case _: C => "C"
    case _ => "default"
  }
Run Code Online (Sandbox Code Playgroud)