Scala/表达式,而非语句
通常,我们需要对变量应该实例化的值做出一个简单的决定。以一个有点人为的例子为例
var result = ""
if(marks >= 50)
result = "passed"
else
result = "failed"
println("Your results just came in, you " + result + ".")
乍一看,它似乎还不错。但如果分支本身评估了一个值,我们可以做得更好。
println("Your results just came in, you " +
(if(marks >= 50) "passed" else "failed") + ".")
事实上,Java/C# 为你提供了(...) ? (...) : (...)语法仅仅因为它在某些时候非常方便。
通常,这个结构可以节省 Scala 程序员为一个短命的变量发明一个愚蠢的名称。也许同样重要的是,它一开始没有给它分配一个愚蠢的值。
当然,如果该值不止一次被需要,你可能应该引入一个值。即使这样,
val result: String = if(marks >= 50) "passed" else "failed"
println("Your results just came in, you " + result + ".")
println("Your academic record now shows that you have " + result + " the course.")
这并不阻止你使用if ... else ...作为语句。毕竟,语句是表达式。
可以理解的是if ... else if ... else ...链同样常见,它们在 Scala 中也同样有效。为了获得更精细的结果,我们可能会尝试,
val result: String =
if(marks >= 85)
"A"
else if(marks >= 70)
"B"
else if(marks >= 60)
"C"
else if(marks >= 50)
"D"
else
"F"
println("You've got " + result + ".")
但更多时候,我们需要根据值而不是条件进行分支。基本上这就是我们拥有switch在 Java/C# 中。Scala 使用match为此,
val result: String =
if(marks >= 85)
"A"
else if(marks >= 70)
"B"
else if(marks >= 60)
"C"
else if(marks >= 50)
"D"
else
"F"
println("You've got " + result + ".")
result match {
case "A" | "B" => println("Congratulations!")
case "C" => println("There is room for improvement, though.")
case _ => println("We are concerned about your progress.")
}
有几件事看起来不同。首先,这些案例不使用break来指示分支的结束。你没有贯穿。不是说你需要贯穿。它们使程序更难阅读和理解。但是,你可以将等效的案例分组,以便可以处理贯穿的主要用途switch语句。虽然 Scala 没有default关键字,下划线读作“其他任何东西”,可以这么说。
如果你出于某种原因在 Java 1.6 或更低版本中尝试过,你可能会注意到另一个区别。switch只处理基本类型(以及String从 Java 1.7 开始)因此一个直接的转换将不得不使用if链与几个equals调用。Scala *使用*equals来匹配对象的案例,以使代码更易于阅读。
我们必须在这里和那里说更多关于match在这本书中。现在,你可能会欣赏将条件语句和案例混合起来以处理非常特殊情况的能力,例如,
case "D" if marks < 52 => println("Close call!")
尽管为了有意义,这种情况应该位于默认情况之上。
即使是try ... catch ...块在 Scala 中也是一个表达式,这会导致非常易读的代码
val n: Int = try {
userInput.toInt
} catch {
case _ => 0
}
顺便说一下,请注意catch看起来很像match(这里下划线表示我们不在乎抛出了哪个特定的异常)。