Почему переменная не может быть стабильным идентификатором?
Следующие
def mMatch(s: String) = {
var target: String = "a"
s match {
case `target` => println("It was " + target)
case _ => println("It was something else")
}
}
не компилируется:
ошибка: требуется стабильный идентификатор, но найдена цель. case target
= > println ( "Это была" + цель ")
Почему Scala требует val
не a var
. Я предполагаю, что "Потому что" будет приемлемым ответом, но у меня есть ощущение, что есть более глубокая причина, по которой мне не хватает.
Ответы
Ответ 1
Я подозреваю, что он позволяет оптимизировать оптимизацию таблиц для тех случаев, когда это возможно (без груды проверки, чтобы проверить, действительно ли это). Например, с кодом
class Sw {
def m(i: Int) = {
val a = 3
val b = 2
val c = 1
i match {
case `a` => 0
case `b` => -1
case `c` => 4
case _ => 2
}
}
}
вы получаете байт-код
public int m(int);
Code:
0: iconst_3
1: istore_2
2: iconst_2
3: istore_3
4: iconst_1
5: istore 4
7: iload_1
8: istore 5
10: iload 5
12: tableswitch{ //1 to 3
1: 48;
2: 44;
3: 52;
default: 40 }
40: iconst_2
41: goto 53
44: iconst_m1
45: goto 53
48: iconst_4
49: goto 53
52: iconst_0
53: ireturn
что было бы намного сложнее сделать, если бы вы использовали vars (вам нужно было бы определить, изменились ли они, чтобы знать, все ли это выражение таблицы).
Ответ 2
Нет ничего, чтобы остановить вас, просто превратив ваш var в val, прежде чем использовать его в матче:
def mMatch(s: String) = {
var target: String = "a"
val x = target
s match {
case `x` => println("It was " + target)
case _ => println("It was something else")
}
}
работает отлично.
Ответ 3
Мое предположение: стабильные идентификаторы требуются в качестве упрощения, чтобы избежать ситуаций, когда переменная изменяется внутри самого шаблона. Это потребует уточнения в спецификации и нарушает оптимизацию, как упоминает Рекс Керр.
var x: String = "a"
"b" match {
case `x` if { x = "b"; true } => println("success")
}
Изменить. Но это объяснение не является полностью удовлетворительным, поскольку стабильный идентификатор может ссылаться на изменяемый объект,
val x = collection.mutable.Seq(2)
def f(y: Seq[Int]) {
y match {
case `x` if { x(0) = 3; true } => println("success")
}
}
f(Seq(2)) // success
f(Seq(2)) // failure
Обратите внимание, что стабильный идентификатор не обязательно известен статически. Например, следующее прекрасно,
def f(x: Int) {
1 match { case `x` => println("hi") }
}