4

我一定对 Scala 的“匹配”语义或编译器逻辑有一些基本的误解。这段代码:

val stageStart:Int = 0
val stageShutDown:Int = Int.MaxValue
val stageErrorReport:Int = Int.MinValue

def stageString(stage:Int):String = stage match {
  case stageStart       => "Start"
  case stageShutDown    => "End"
  case stageErrorReport => "Error"
  case _                => "Step " + String.valueOf(stage)
}

在最后 3 个“案例”语句中导致“无法访问代码”错误?如果您用实际值(0、Int.MaxValue、Int.MinValue)代替名称,它会编译——但现在我已经硬编码了应该由它们的名称引用的值(出于所有通常的原因)。既然“val”永远不会改变,那么第一个版本不应该也可以吗?

4

2 回答 2

9

有一个微妙而重要的特性:如果case规则中的标识符以小写字母开头,它们总是被视为变量。所以第一个case匹配总是(存储stage到变量stageStart中),其余的 3 个是无法访问的。您需要将带有大写字母的常量定义为

val StageStart:Int = 0
val StageShutDown:Int = Int.MaxValue
val StageErrorReport:Int = Int.MinValue

def stageString(stage:Int):String = stage match {
  case StageStart       => "Start"
  case StageShutDown    => "End"
  case StageErrorReport => "Error"
  case _                => "Step " + String.valueOf(stage)
}

然后它们不会被视为变量,而是作为模式匹配的常量。

另请参阅此答案了解 Scala 常量的命名约定?

于 2012-08-29T18:32:07.757 回答
8

问题是当您使用以小写字符开头的变量时,模式匹配器认为您正在尝试分配给该变量。所以你会得到这种行为:

val stageStart = 0
val stage = 5
def stageString(stage: Int) = stage match {
  case stageStart => println(startStage)  // prints "5"
}

当然,只是一个可赋值变量的模式将匹配任何东西,因此任何后续case都将无法访问。

要解决这个问题,您需要使用“稳定标识符”。这可以通过将小写变量放在反引号中来完成:

val stageStart = 0
def stageString(stage: Int) = stage match {
  case `stageStart` => "Start"
}

或重命名变量,使其以大写字符开头:

val StageStart = 0
def stageString(stage: Int) = stage match {
  case StageStart => "Start"
}

另外:String.valueOf(stage)应该改写为stage.toString.

于 2012-08-29T18:32:18.163 回答