对scala'match'编译规则的误解

use*_*503 4 scala compiler-errors match

我必须对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)
}
Run Code Online (Sandbox Code Playgroud)

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

Pet*_*lák 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)
}
Run Code Online (Sandbox Code Playgroud)

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

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


dhg*_*dhg 8

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

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

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

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

val stageStart = 0
def stageString(stage: Int) = stage match {
  case `stageStart` => "Start"
}
Run Code Online (Sandbox Code Playgroud)

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

val StageStart = 0
def stageString(stage: Int) = stage match {
  case StageStart => "Start"
}
Run Code Online (Sandbox Code Playgroud)

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