对 scala"匹配"编译规则的误解



我一定对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个"case"语句出现"Unreachable Code"错误?如果它编译的不是名称而是实际值(0、Int.MaxValue、Int.MinValue),但现在我已经硬编码了应该由它们的名称引用的值(出于所有常见原因)。既然"val"永远不会改变,那么第一个版本不应该也工作吗?

有一个微妙但重要的特性:如果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常量的命名约定,请参阅以下答案?

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

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

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

为了解决这个问题,您需要使用一个"稳定的标识符"。这可以通过在backtick:中放入小写变量来实现

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

最新更新