2010-12-18 13 views
13

he encontrado que cuando se utiliza la coincidencia de patrones con alternativas (por cadenas), Scala acepta las variables a partir de caso superior (en el ejemplo siguiente, MyValue1 y MyValue2), pero no los que empiezan con el caso inferior (myValue1, myValue2). ¿Es esto un error o una característica de Scala? Lo entiendo en la versión 2.8. Si esta es una característica, ¿alguien puede explicar la razón detrás de esto? Este es el código que utilicé:patrón Scala a juego con nombre de la variable en minúsculas

val myValue1 = "hello" 
val myValue2 = "world" 
val MyValue1 = "hello" 
val MyValue2 = "world" 

var x:String = "test" 

x match { 
    case MyValue1 | MyValue2 => println ("first match") 
    case myValue1 | myValue2 => println ("second match") 
} 

corriendo, me sale el siguiente:

scala> val myValue1 = "hello" 
myValue1: java.lang.String = hello 

scala> val myValue2 = "world" 
myValue2: java.lang.String = world 

scala> val MyValue1 = "hello" 
MyValue1: java.lang.String = hello 

scala> val MyValue2 = "world" 
MyValue2: java.lang.String = world 

scala> var x:String = "test" 
x: String = test 

scala> x match { 
| case MyValue1 | MyValue2 => println ("first match") 
| case myValue1 | myValue2 => println ("second match") 
| } 
<console>:11: error: illegal variable in pattern alternative 
    case myValue1 | myValue2 => println ("second match") 
     ^
<console>:11: error: illegal variable in pattern alternative 
    case myValue1 | myValue2 => println ("second match") 
        ^

EDITAR:

Por lo tanto, es de hecho una característica y no un error ... ¿Alguien puede dar un ejemplo cuando esto podría ser útil?

Cuando uso:

x match { 
    case myValue1 => println ("match") 
    case _ => 
} 

me sale un aviso unreachable code en el último caso, lo que implica que el primero siempre coincide.

+4

Este es uno de los errores comunes de programación en Scala: http://stackoverflow.com/questions/1332574/common- programación-errors-for-scala-developers-to-avoid/2489355 # 2489355. Recomiendo leer todo el hilo, tiene un montón de otros problemas como este. – Steve

+0

Gracias por la gran referencia. – Jus12

+0

Un ejemplo útil: 'x match {case myValue1: String => println (" match: "+ myValue1); case _ =>} '-> myValue1 se convierte en una variable local. – Madoc

Respuesta

33

Esto no es específico de los patrones con alternativas, y no es un error. Un identificador que comienza con una letra minúscula en un patrón representa una nueva variable que se vinculará si el patrón coincide.

lo tanto, su ejemplo es equivalente a la escritura:

x match { 
    case MyValue1 | MyValue2 => println ("first match") 
    case y | z => println ("second match") 
} 

Puede solucionar esto mediante el uso acentos abiertos:

x match { 
    case MyValue1 | MyValue2 => println ("first match") 
    case `myValue1` | `myValue2` => println ("second match") 
} 
+0

Esta es una característica muy sutil y muchos posiblemente pensarán que es un error. Seleccionado como la respuesta para dar la solución. – Jus12

5

Lo que está sucediendo aquí es que myValue1 y myValue2 están siendo tratados como identificadores de variable (es decir, la definición de nuevas variables que están vinculadas al valor que se corresponde), mientras que MyValue1 y MyValue2 se tratan como identificadores estables que hacen referencia a valores declarados más temprano. En un caso de coincidencia de patrones, los identificadores de variables deben comenzar con una letra minúscula, de ahí que el primer caso se comporte intuitivamente. Consulte la sección 8.1 de la Especificación del idioma de Scala (http://www.scala-lang.org/docu/files/ScalaReference.pdf) para obtener detalles exactos.

La alteración de su ejemplo un poco, se puede ver la variable de identificación:

scala> x match { 
| case MyValue1 | MyValue2 => println ("first match") 
| case myValue1 => println (myValue1) 
| } 
test 
+0

Gracias por la referencia. La sección exacta es 8.1.1. Solo pude elegir una respuesta correcta. – Jus12

6

Es una característica. Los identificadores estables que comienzan con una letra mayúscula se tratan como literales a los fines de la coincidencia de patrones, y los identificadores en minúscula se "asignan a" para que pueda usar el valor coincidente para otra cosa.

diste un ejemplo de no tener sentido:

x match { 
    case myValue1 => println ("match") 
    case _ => 
} 

Pero el sentido es fácil ver si cambiamos de que un poco:

x match { 
    case MyValue1 => println("match") 
    case MyValue2 => println("match") 
    case other => println("no match: "+other) 
} 

Por supuesto, se podría utilizar x vez de other anterior, pero aquí hay algunos ejemplos en los que no sería conveniente:

(pattern findFirstIn text) { 
    // "group1" and "group2" have been extracted, so were not available before 
    case pattern(group1, group2) => 

    // "other" is the result of an expression, which you'd have to repeat otherwise 
    case other => 
} 

getAny match { 
    // Here "s" is a already a string, whereas "getAny" would have to be typecast 
    case s: String => 

    // Here "i" is a already an int, whereas "getAny" would have to be typecase 
    case i: Int => 
} 

Por lo tanto, hay muchas razones por las que es conveniente que la coincidencia de patrones asigne el valor coincidente a un identificador.

Ahora, aunque creo que esta es una de las mayores fallas de Scala, porque es tan sutil y única, el razonamiento detrás de esto es que, en el estilo Scala recomendado, las constantes son en camello comenzando con una letra mayúscula, mientras que los métodos y vals y vars (que en realidad son métodos también) son enchapados en camello empezando con letras minúsculas. Por lo tanto, las constantes se tratan naturalmente como literales, mientras que otras se tratan como identificadores asignables (que pueden sombrear identificadores definidos en un contexto externo).

Cuestiones relacionadas