Warum funktioniert der Mustervergleich in Scala nicht mit Variablen?

113

Übernehmen Sie die folgende Funktion:

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

Dieses Muster passt gut:

scala> fMatch("a")
It was a

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

Was ich tun möchte, ist Folgendes:

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

Dies gibt den folgenden Fehler aus:

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

Ich denke, das liegt daran, dass das Ziel tatsächlich ein Name ist, den Sie der Eingabe zuweisen möchten. Zwei Fragen:

  1. Warum dieses Verhalten? Können Sie nicht einfach nach vorhandenen Variablen im Gültigkeitsbereich suchen, die den entsprechenden Typ haben, und diese zuerst verwenden. Wenn keine gefunden werden, behandeln Sie das Ziel als einen Namen, über den das Muster abgeglichen werden soll.

  2. Gibt es eine Problemumgehung dafür? Gibt es eine Möglichkeit, Muster mit Variablen abzugleichen? Letztendlich könnte man eine große if-Aussage gebrauchen, aber der Matchcase ist eleganter.

Henry Henrinson
quelle
Siehe auch
Dave L.
1
Ich glaube, diese Frage, der Code und die Antworten sind ab Scala 2.12.x veraltet. Es wäre schön, wenn die Version, für die gilt, als Teil der Frage erwähnt würde.
Conny

Antworten:

217

Was Sie suchen, ist eine stabile Kennung . In Scala müssen diese entweder mit einem Großbuchstaben beginnen oder von Backticks umgeben sein.

Beides wäre eine Lösung für Ihr Problem:

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")
    }
}

Um zu vermeiden, dass versehentlich auf Variablen verwiesen wird, die bereits im umschließenden Bereich vorhanden waren, ist es meines Erachtens sinnvoll, dass das Standardverhalten darin besteht, dass Kleinbuchstaben Variablen und keine stabilen Bezeichner sind. Nur wenn Sie etwas sehen, das mit Großbuchstaben beginnt, oder in Häkchen, müssen Sie sich bewusst sein, dass es aus dem umgebenden Bereich stammt.

Ben James
quelle
3
Ich wette, das kommt aus Erlang, wo Variablen mit einem Großbuchstaben und Symbole mit Kleinbuchstaben beginnen.
Emil Ivanov
11
Beachten Sie, dass dies targetein Wert ( val) und keine Variable ( var) ist. Es funktioniert nicht mit Variablen.
Luigi Plinge
Großbuchstaben? Schatten von FORTRAN. Schwach, Martin, schwach.
Malvolio
13
@Emil Tatsächlich bezeichnen großgeschriebene Bezeichner in Scala Konstanten. Unter einem Mustervergleich für einen Bezeichner in Großbuchstaben wird also der Vergleich mit einer Konstanten verstanden. Es hilft ernsthaft bei Sachen wie Nil, was ich wette, ist der wahre Grund.
Daniel C. Sobral
Es scheint, als könne man keine thisstabile Kennung verwenden, um eine Übereinstimmung mit dem Muster zu erzielen. Es scheint nur so, als würde man einen Gleichstellungsschutz wie verwenden case x if x == this =>. Wahrscheinlich eine syntaktische Einschränkung, sonst sollte es zumindest innerhalb von objects semantisch funktionieren .
Nader Ghanbari