2011-09-27 416 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 
}