Почему сопоставление с образцом в Scala не работает с переменными?


113

Возьмем следующую функцию:

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

Этот шаблон хорошо сочетается:

scala> fMatch("a")
It was a

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

Что я хотел бы сделать, так это следующее:

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

Это дает следующую ошибку:

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

Я предполагаю, что это потому, что он думает, что цель - это на самом деле имя, которое вы хотели бы присвоить любому входу. Два вопроса:

  1. Почему такое поведение? Разве нельзя просто искать существующие переменные в области видимости, которые имеют соответствующий тип, и использовать их в первую очередь, а если ни одна не найдена, то рассматривать цель как имя для сопоставления с образцом?

  2. Есть ли обходной путь для этого? Есть ли способ сопоставить шаблон с переменными? В конечном итоге можно использовать большой оператор if, но регистр совпадений более элегантен.



1
Я считаю, что этот вопрос, код и ответы устарели в Scala 2.12.x. Было бы неплохо, если бы версия, к которой она применяется, была упомянута как часть вопроса.
conny

Ответы:


218

Вам нужен стабильный идентификатор . В Scala они должны начинаться с заглавной буквы или заключаться в обратные кавычки.

Оба из них будут решениями вашей проблемы:

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

Чтобы избежать случайной ссылки на переменные, которые уже существовали во включающей области, я думаю, имеет смысл, что по умолчанию строчные шаблоны должны быть переменными, а не стабильными идентификаторами. Только когда вы видите что-то, начинающееся с верхнего регистра или наоборот, вам нужно знать, что оно исходит из окружающей области.


3
Бьюсь об заклад, это происходит из Erlang, где переменные начинаются с заглавной буквы, а символы - с строчной.
Эмиль Иванов

11
Обратите внимание, что targetэто значение ( val), а не переменная ( var). Он не работает с переменными.
Луиджи Плиндж

Верхний регистр? Оттенки ФОРТРАНА. Слаб, Мартин, слаб.
Мальволио

13
@Emil На самом деле, идентификаторы с заглавной буквы в Scala обозначают константы. Таким образом, сопоставление с шаблоном идентификатора в верхнем регистре означает сравнение с константой. Это серьезно помогает в подобных вещах Nil, и я уверен, что это настоящая причина.
Дэниел С. Собрал

Похоже, что нельзя использовать thisв качестве стабильного идентификатора для сопоставления с ним шаблона, кажется, единственный способ использовать защиту равенства, например case x if x == this =>. Вероятно, синтаксическое ограничение, иначе он должен семантически работать хотя бы в пределах objects.
Надер Ганбари
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.