模式匹配多个匹配

时间:2011-09-27 07:29:41

标签: scala pattern-matching

考虑以下Scala代码。

val a = "both"

a match {
    case "both" | "foo" => println ("foo")   // case 1
    case "both" | "bar" => println ("bar")   // case 2
}

我希望match能够工作,这样如果a == "both",Scala就会执行这两种情况。这是可能的还是有任何替代方案可以达到我的目的?

5 个答案:

答案 0 :(得分:25)

标准模式匹配将始终仅匹配一个案例。通过使用模式可以被视为部分函数(参见Language Specification,第8.5节,模式匹配匿名函数)并定义自己的匹配,您可以接近您想要的内容但是,运营商:

class MatchAll[S](scrutinee : =>S) {
  def matchAll[R](patterns : PartialFunction[S,R]*) : Seq[R] = {
    val evald : S = scrutinee
    patterns.flatMap(_.lift(evald))
  }
}

implicit def anyToMatchAll[S](scrut : =>S) : MatchAll[S] = new MatchAll[S](scrut)

def testAll(x : Int) : Seq[String] = x matchAll (
  { case 2 => "two" },
  { case x if x % 2 == 0 => "even" },
  { case x if x % 2 == 1 => "neither" }
)

println(testAll(42).mkString(",")) // prints 'even'
println(testAll(2).mkString(","))  // prints 'two,even'
println(testAll(1).mkString(","))  // prints 'neither'

语法略微偏离平常,但对我而言,这样的结构仍然是Scala力量的见证。

您的示例现在写为:

// prints both 'foo' and 'bar'
"both" matchAll (
  { case "both" | "foo" => println("foo") },
  { case "both" | "bar" => println("bar") }
)

编辑 huynhjl指出他对this question给出了一个惊人相似的答案。)

答案 1 :(得分:6)

冒着成为明显上尉的风险,在这样的情况下,忘记模式匹配并使用if是最简单的。

if (a == "both" || a == "foo") println("foo")
if (a == "both" || a == "bar") println("bar") 

如果重复a ==让你担心,你可以改写

if (Set("both", "foo")(a)) println("foo")
if (Set("both", "bar")(a)) println("bar")

使用apply上的Set方法与contains的方法相同,并且有点短。

答案 2 :(得分:3)

match执行一个且只有一个案例,因此您无法在匹配中执行or。但是,您可以使用列表和map / foreach

val a = "both"
(a match {
  case "both" => List("foo", "bar")
  case x => List(x)
}) foreach(_ match {
  case "foo" => println("foo")
  case "bar" => println("bar")
})

并且您没有复制任何重要代码(在本例中为println)。

答案 3 :(得分:1)

只是匹配两次:

val a = "both"

a match {
    case "both" | "foo" => println ("foo")   // Case 1
}
a match {
    case "both" | "bar" => println ("bar")   // Case 2
}

答案 4 :(得分:0)

一种可能的方法是:

val a = "both"

a match {
  case "foo" => println ("foo")   // Case 1
  case "bar" => println ("bar")   // Case 2
  case "both" => println ("foo"); println ("bar")
}