为什么变量不能是稳定的标识符?

时间:2011-08-16 18:56:20

标签: scala

以下

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。我猜“因为”是一个可以接受的答案,但我觉得我错过了更深层次的原因。

3 个答案:

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