Dlaczego dopasowywanie wzorców w Scali nie działa ze zmiennymi?

113

Weź następującą funkcję:

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

Ten wzór ładnie pasuje:

scala> fMatch("a")
It was a

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

Chciałbym móc wykonać następujące czynności:

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

Powoduje to następujący błąd:

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

Wydaje mi się, że dzieje się tak, ponieważ uważa, że ​​cel jest w rzeczywistości nazwą, którą chcesz przypisać do tego, co jest na wejściu. Dwa pytania:

  1. Dlaczego to zachowanie? Czy nie można po prostu poszukać istniejących zmiennych w zakresie, które mają odpowiedni typ i użyć ich najpierw, a jeśli nie zostaną znalezione, potraktować cel jako nazwę do dopasowania do wzorca?

  2. Czy istnieje obejście tego problemu? Jakiś sposób na dopasowanie wzorca do zmiennych? Ostatecznie można by użyć dużego stwierdzenia if, ale opakowanie zapałek jest bardziej eleganckie.

Henry Henrinson
źródło
1
Uważam, że to pytanie, kod i odpowiedzi są nieaktualne od wersji Scala 2.12.x. Byłoby miło, gdyby wersja, której dotyczy, została wymieniona jako część pytania.
conny

Odpowiedzi:

217

To, czego szukasz, to stabilny identyfikator . W Scali muszą one zaczynać się od dużej litery lub być otoczone grawitacjami.

Oba rozwiązania byłyby rozwiązaniem Twojego problemu:

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

Aby uniknąć przypadkowego odwoływania się do zmiennych, które już istniały w obejmującym zakresie, myślę, że ma sens, aby domyślnym zachowaniem wzorce z małych liter były zmienne, a nie stabilne identyfikatory. Tylko wtedy, gdy widzisz coś zaczynającego się od dużej litery lub od tyłu, musisz mieć świadomość, że pochodzi z otaczającego zakresu.

Ben James
źródło
3
Założę się, że pochodzi z Erlang, gdzie zmienne zaczynają się od dużej litery, a symbole od małych.
Emil Iwanow
11
Zauważ, że targetjest to wartość ( val), a nie zmienna ( var). Nie działa ze zmiennymi.
Luigi Plinge
Duże litery? Odcienie FORTRAN. Słaby, Martin, słaby.
Malvolio
13
@Emil Właściwie, duże identyfikatory w Scali oznaczają stałe. Zatem dopasowanie wzorca w identyfikatorze wielkiej litery oznacza porównanie ze stałą. To poważnie pomaga w takich rzeczach Nil, które mi zakład jest prawdziwy powód.
Daniel C. Sobral,
Wygląda na to, że nie można użyć thisstabilnego identyfikatora do dopasowania wzorca do niego, jedynym sposobem wydaje się być użycie takiego zabezpieczenia równości case x if x == this =>. Prawdopodobnie ograniczenie składniowe, w przeciwnym razie powinno działać semantycznie przynajmniej w ciągu objects.
Nader Ghanbari,