2011-09-27 18 views
11

Tenga en cuenta el siguiente código de Scala.Coincidencia de patrón con más de una coincidencia

val a = "both" 

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

me gustaría match a trabajar de manera que si a == "both", Scala ejecutará ambos casos. ¿Es esto posible o hay alternativas para lograr lo que quiero?

+0

posible duplicado del [Partido "fallthrough": la ejecución misma pieza de código para más de un caso] (http://stackoverflow.com/questions/2325863/match- fallthrough-execute-same-piece-of-code-for-more-than-one-case) – nawfal

Respuesta

25

La coincidencia de patrones estándar siempre coincidirá solo en exactamente un caso. Puede estar cerca de lo que desea realizar con el hecho de que los patrones pueden ser tratados como funciones parciales (ver el Language Specification, Sección 8.5, coincidencia de patrón funciones anónimas) y la definición de su propio operador de juego, sin embargo:

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' 

La sintaxis es ligeramente diferente a la habitual, pero para mí una construcción así sigue siendo un testimonio del poder de Scala.

Su ejemplo está escrito como:

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

(Editarhuynhjl señaló que dio una respuesta terriblemente similar a this question.)

+1

Esta es una solución sorprendentemente limpia. ¡Bien hecho! –

+1

+1 para "scrutinee" –

+1

Esto me recuerda a http://stackoverflow.com/questions/6720205/idiomatic-way-to-convert-a-seqb/6720659#6720659. ¿Cuál es el beneficio del nombre '=> S'? – huynhjl

0

Una manera posible podría ser:

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 ejecuta uno, y sólo uno, de los casos, por lo que no puede hacer esto como una or en el partido. Puede, sin embargo, utilizar una lista y 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") 
}) 

Y usted no está duplicando cualquier parte del código importante (en este caso los println s).

6

en riesgo de ser Capitán Obvio, en un caso así, sería más simple olvidar la coincidencia de patrones y usar if.

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

Si la repetición de a == preocupaciones que, en su lugar podría escribir

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

usando el hecho de que el método apply en Set hace lo mismo que contains, y es un poco más corto.

1

Sólo coinciden dos veces:

val a = "both" 

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