2011-09-27 325 views
11

请考虑以下Scala代码。与多个匹配匹配的模式

val a = "both" 

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

我想match工作,所以,如果a == "both",斯卡拉将执行两种情况。这是可能的还是有其他方法可以实现我想要的?

+0

可能重复的[匹配“下通”:执行同一段代码多于一个的情况下(http://stackoverflow.com/questions/2325863/match-执行同一个代码的情况下,执行多于一种情况) – nawfal

回答

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

这是一个非常干净的解决方案。做得好! –

+1

+1“scrutinee” –

+1

这让我想起http://stackoverflow.com/questions/6720205/idiomatic-way-to-convert-a-seqb/6720659#6720659。名字'=> S'有什么好处? – huynhjl

0

一种可能的方式可以是:

val a = "both" 

a match { 
    case "foo" => println ("foo") // Case 1 
    case "bar" => println ("bar") // Case 2 
    case "both" => println ("foo"); println ("bar") 
} 
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 S)。

6

在被船长明显的风险,在的情况下,像这样,忘记模式匹配并使用if将是最简单的。

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

如果a ==后顾之忧重复你,你可以不使用的事实,上Setapply方法不一样contains,是一个有点短写

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

1

仅有匹配两次:

val a = "both" 

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