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.



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.


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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.