我一定对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
。