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

Mal*_*lio 36 scala

下列

def mMatch(s: String) = {
    var target: String = "a"
    s match {
        case `target` => println("It was " + target)
        case _ => println("It was something else")
    }
}
Run Code Online (Sandbox Code Playgroud)

不编译:

错误:需要稳定的标识符,但找到了目标.case target=> println("它是"+目标)

为什么Scala需要val不是a var.我猜"因为"是一个可以接受的答案,但我觉得我错过了更深层次的原因.

Rex*_*err 41

我怀疑它是为那些可能的情况启用表切换优化(没有成堆检查以查看它是否有效).例如,使用代码

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
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

你得到字节码

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
Run Code Online (Sandbox Code Playgroud)

如果你使用vars会更复杂(你必须检测它们是否已经改变以知道该表表达式是否仍然有效).


Lui*_*hys 13

在匹配中使用它之前,没有什么能阻止你将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")
    }
}
Run Code Online (Sandbox Code Playgroud)

工作得非常好.

  • 究竟.如果*I*可以做到,为什么编译器不能这样做呢? (20认同)

Kip*_*ros 10

我的猜测是需要稳定的标识符作为简化,以避免变量在匹配自身的模式内发生变化.这需要在规范中加以澄清,并且如Rex Kerr所提到的那样破坏优化.

var x: String = "a"
"b" match {
  case `x` if { x = "b"; true } => println("success")
}
Run Code Online (Sandbox Code Playgroud)

编辑.但是这种解释并不完全令人满意,因为稳定的标识符可以指一个可变对象,

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
Run Code Online (Sandbox Code Playgroud)

注意,稳定的标识符不一定是静态已知的.例如,以下是好的,

def f(x: Int) {
  1 match { case `x` => println("hi") }
}
Run Code Online (Sandbox Code Playgroud)