【问题标题】:Why can't a variable be a stable identifier?为什么变量不能是稳定的标识符?
【发布时间】:2011-08-16 18:56:19
【问题描述】:

以下

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("它是" + target)

为什么 Scala 需要 val 而不是 var。我想“因为”是一个可以接受的答案,但我觉得我错过了更深层次的原因。

【问题讨论】:

    标签: scala


    【解决方案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,这将更加复杂(您必须检测它们是否已更改才能知道该表表达式是否仍然有效)。

    【讨论】:

    • 这是不正确的。模式匹配不一定使用开关。其实有@switch注解要保证使用tableswitch或者lookupswitch就可以了。
    • @PaulDraper - 我认为您正在阅读我没有说的内容。如果您希望始终拥有使用功能 X 的选项,则需要始终满足先决条件。我从来没有说过开关总是被使用的!
    • @RexKerr,我可能看错了。但无论如何,不​​管有没有稳定的标识符,有时会使用开关,有时不会。 (具体来说,如果没有稳定的标识符,它们就不会被使用。)我可以理解为什么不稳定的标识符不能轻松地与 switches 一起使用,而不是为什么不稳定的标识符不能轻松地与 pattern 匹配一起使用.
    • @PaulDraper - 我的意思是我怀疑这样会更容易:如果标识符稳定,代码分析会更简单,并且您需要代码分析来判断 tableswitch 是可能的。它是启用的,不是必需的。
    【解决方案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】:

    我的猜测是需要稳定的标识符作为简化以避免模式匹配本身内部变量发生变化的情况。这需要在规范中进行澄清,并破坏 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") }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-17
      • 1970-01-01
      • 2013-04-20
      • 1970-01-01
      • 1970-01-01
      • 2014-11-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多