Why can't a variable be a stable identifier?
The following
def mMatch(s: String) = {
var target: String = "a"
s match {
case `target` => println("It was " + target)
case _ => println("It was something else")
}
}
does not compile:
error: stable identifier required, but target found. case
target
=> println("It was " + target)
Why does Scala require a val
not a var
. I guess "Because" would be an acceptable answer but I have the feeling there is a deeper reas开发者_如何学Con I am missing.
I suspect that it's to enable table-switching optimizations for those cases where it is possible (without piles of checking to see whether it's valid). For example, with the code
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
}
}
}
you get the bytecode
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
which would be much more complicated to do if you used vars (you'd have to detect whether they had changed to know whether that table expression was still valid).
There's nothing to stop you just turning your var into a val before using it in the match:
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")
}
}
works perfectly fine.
My guess is stable identifiers are required as a simplification to avoid situations where the variable changes inside the pattern matching itself. This would require clarification in the spec, and disrupt optimizations as Rex Kerr mentions.
var x: String = "a"
"b" match {
case `x` if { x = "b"; true } => println("success")
}
Edit. But this explanation is not completely satisfactory, because the stable identifier could refer to a mutable object,
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
Note that a stable identifier is not necessarily known statically. For example, the following is fine,
def f(x: Int) {
1 match { case `x` => println("hi") }
}
精彩评论