Почему переменная не может быть стабильным идентификатором?

Следующие

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