Perché il pattern matching in Scala non funziona con le variabili?


113

Assumi la seguente funzione:

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

Questo modello corrisponde bene:

scala> fMatch("a")
It was a

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

Quello che vorrei poter fare è quanto segue:

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

Questo emette il seguente errore:

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

Immagino che questo sia perché pensa che l'obiettivo sia in realtà un nome che vorresti assegnare a qualunque sia l'input. Due domande:

  1. Perché questo comportamento? Non è possibile cercare solo le variabili esistenti nell'ambito che hanno un tipo appropriato e utilizzare prima quelle e, se non ne viene trovata nessuna, trattare l'obiettivo come un nome su cui eseguire il patternmatch?

  2. C'è una soluzione alternativa per questo? Qualche modo per trovare un pattern match contro le variabili? Alla fine si potrebbe usare un'istruzione if grande, ma le maiuscole sono più eleganti.



1
Credo che questa domanda, il codice e le risposte siano obsolete a partire da Scala 2.12.x. Sarebbe bello se la versione a cui si applica fosse menzionata come parte della domanda.
conny

Risposte:


217

Quello che stai cercando è un identificatore stabile . In Scala, questi devono iniziare con una lettera maiuscola o essere circondati da backtick.

Entrambe queste sarebbero soluzioni al tuo 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")
    }
}

Per evitare di fare riferimento accidentalmente a variabili che già esistevano nello scope di inclusione, penso che abbia senso che il comportamento predefinito sia che i modelli minuscoli siano variabili e non identificatori stabili. Solo quando vedi qualcosa che inizia con le lettere maiuscole o con i segni di spunta, devi essere consapevole che proviene dall'ambito circostante.


3
Scommetto che proviene da Erlang, dove le variabili iniziano con una lettera maiuscola e i simboli con una minuscola.
Emil Ivanov

11
Notare che targetè un valore ( val) e non una variabile ( var). Non funziona con le variabili.
Luigi Plinge

Maiuscolo? Sfumature di FORTRAN. Debole, Martin, debole.
Malvolio

13
@ Emil In realtà, gli identificatori in maiuscolo in Scala denotano costanti. Quindi un modello di corrispondenza su un identificatore maiuscolo viene considerato come un confronto con una costante. Aiuta seriamente con roba come Nil, che io scommessa è la vera ragione.
Daniel C. Sobral,

Sembra che non si possa usare thiscome identificatore stabile per pattern match contro di esso, l'unico modo sembra usare una guardia di uguaglianza come case x if x == this =>. Probabilmente una limitazione sintattica, altrimenti dovrebbe funzionare semanticamente almeno entro objects.
Nader Ghanbari
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.