¿Por qué la coincidencia de patrones en Scala no funciona con variables?

113

Toma la siguiente función:

def fMatch(s: String) = {
    s match {
        case "a" => println("It was a")
        case _ => println("It was something else")
    }
}

Este patrón combina muy bien:

scala> fMatch("a")
It was a

scala> fMatch("b")
It was something else

Lo que me gustaría poder hacer es lo siguiente:

def mMatch(s: String) = {
    val target: String = "a"
    s match {
        case target => println("It was" + target)
        case _ => println("It was something else")
        }
}

Esto emite el siguiente error:

fMatch: (s: String)Unit
<console>:12: error: unreachable code
               case _ => println("It was something else")

Supongo que esto se debe a que cree que target es en realidad un nombre que le gustaría asignar a cualquier entrada. Dos preguntas:

  1. ¿Por qué este comportamiento? ¿No puede el caso simplemente buscar las variables existentes en el alcance que tengan el tipo apropiado y usarlas primero y, si no se encuentra ninguna, luego tratar el objetivo como un nombre para hacer coincidir el patrón?

  2. ¿Hay una solución para esto? ¿Alguna forma de hacer coincidir el patrón con las variables? En última instancia, uno podría usar una gran declaración if, pero el caso de coincidencia es más elegante.

Henry Henrinson
fuente
1
Creo que esta pregunta, código y respuestas están desactualizados a partir de Scala 2.12.x. Sería bueno si la versión a la que se aplica se mencionara como parte de la pregunta.
conny

Respuestas:

217

Lo que busca es un identificador estable . En Scala, estos deben comenzar con una letra mayúscula o estar rodeados de comillas invertidas.

Ambos serían soluciones a su problema:

def mMatch(s: String) = {
    val target: String = "a"
    s match {
        case `target` => println("It was" + target)
        case _ => println("It was something else")
    }
}

def mMatch2(s: String) = {
    val Target: String = "a"
    s match {
        case Target => println("It was" + Target)
        case _ => println("It was something else")
    }
}

Para evitar referirse accidentalmente a variables que ya existían en el ámbito adjunto, creo que tiene sentido que el comportamiento predeterminado sea que los patrones en minúsculas sean variables y no identificadores estables. Solo cuando vea algo que comience con mayúsculas o con tics posteriores, debe tener en cuenta que proviene del alcance circundante.

Ben James
fuente
3
Apuesto a que esto proviene de Erlang, donde las variables comienzan con una letra mayúscula y los símbolos con una minúscula.
Emil Ivanov
11
Observe que targetes un valor ( val) y no una variable ( var). No funciona con variables.
Luigi Plinge
Mayúsculas? Tonos de FORTRAN. Débil, Martín, débil.
Malvolio
13
@Emil En realidad, los identificadores en mayúscula en Scala denotan constantes. Por lo tanto, se considera que una coincidencia de patrones en un identificador en mayúsculas significa comparar con una constante. Realmente ayuda con cosas como Nil, y apuesto a que es la verdadera razón.
Daniel C. Sobral
Parece que no se puede usar thiscomo un identificador estable para un patrón de coincidencia con él, la única forma parece ser usar un protector de igualdad como case x if x == this =>. Probablemente una limitación sintáctica, de lo contrario debería funcionar semánticamente al menos dentro de objects.
Nader Ghanbari