考虑以下Scala代码。
val a = "both"
a match {
case "both" | "foo" => println ("foo") // case 1
case "both" | "bar" => println ("bar") // case 2
}
我希望match
能够工作,这样如果a == "both"
,Scala就会执行这两种情况。这是可能的还是有任何替代方案可以达到我的目的?
答案 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")
}