以下
def mMatch(s: String) = {
var target: String = "a"
s match {
case `target` => println("It was " + target)
case _ => println("It was something else")
}
}
无法编译:
错误:需要稳定的标识符,但找到了目标。 案例
target
=> println(“它是”+目标)
为什么Scala需要val
而不是var
。我猜“因为”是一个可以接受的答案,但我觉得我错过了更深层次的原因。
答案 0 :(得分:40)
我怀疑它是为那些可能的情况启用表切换优化(没有成堆检查以查看它是否有效)。例如,使用代码
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会更复杂(您必须检测它们是否已更改以了解该表表达式是否仍然有效)。
答案 1 :(得分:12)
在比赛中使用它之前,没有什么可以阻止你将你变成一个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")
}
}
完美无缺。
答案 2 :(得分:10)
我的猜测是需要稳定的标识符作为简化,以避免变量在匹配自身的模式内发生变化。这需要在规范中加以澄清,并且如Rex Kerr所提到的那样破坏优化。
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") }
}