Scala 具有你在其他编程语言中发现的控制结构,还具有强大的 for 表达式和 match 表达式
if/elsefor循环和表达式match表达式while循环try/catch
以下示例展示了这些结构。
if/else
Scala 的 if/else 控制结构看起来与其他语言类似。
if (x < 0) {
println("negative")
} else if (x == 0) {
println("zero")
} else {
println("positive")
}
if x < 0 then
println("negative")
else if x == 0 then
println("zero")
else
println("positive")
请注意,这实际上是一个表达式,而不是一个语句。这意味着它返回一个值,因此你可以将结果分配给一个变量
val x = if (a < b) { a } else { b }
val x = if a < b then a else b
正如你在这本书中所看到的,所有 Scala 控制结构都可以用作表达式。
表达式返回一个结果,而语句则不返回。语句通常用于其副作用,例如使用
println打印到控制台。
for 循环和表达式
for 关键字用于创建 for 循环。此示例展示了如何打印 List 中的每个元素
val ints = List(1, 2, 3, 4, 5)
for (i <- ints) println(i)
代码
i <- ints称为生成器。在任何生成器p <- e中,表达式e可以生成零个或多个绑定到模式p的绑定。生成器闭合括号后面的代码是循环的主体。
val ints = List(1, 2, 3, 4, 5)
for i <- ints do println(i)
代码
i <- ints被称为生成器,而do关键字后面的代码是循环的主体。
守卫
你也可以在 for 循环中使用一个或多个 if 表达式。这些被称为守卫。此示例打印 ints 中所有大于 2 的数字
for (i <- ints if i > 2)
println(i)
for
i <- ints
if i > 2
do
println(i)
你可以使用多个生成器和守卫。此循环迭代数字 1 到 3,并且对于每个数字,它还迭代字符 a 到 c。但是,它还有两个守卫,因此仅在 i 的值为 2 且 j 的字符为 b 时才会调用 print 语句
for {
i <- 1 to 3
j <- 'a' to 'c'
if i == 2
if j == 'b'
} {
println(s"i = $i, j = $j") // prints: "i = 2, j = b"
}
for
i <- 1 to 3
j <- 'a' to 'c'
if i == 2
if j == 'b'
do
println(s"i = $i, j = $j") // prints: "i = 2, j = b"
for 表达式
for 关键字功能更强大:当你使用 yield 关键字代替 do 时,你创建了 for 表达式,用于计算并生成结果。
一些示例对此进行了演示。使用与前一个示例相同的 ints 列表,此代码创建一个新列表,其中新列表中每个元素的值是原始列表中元素值的两倍
scala> val doubles = for (i <- ints) yield i * 2
val doubles: List[Int] = List(2, 4, 6, 8, 10)
scala> val doubles = for i <- ints yield i * 2
val doubles: List[Int] = List(2, 4, 6, 8, 10)
Scala 的控制结构语法很灵活,并且 for 表达式可以根据你的喜好以多种其他方式编写
val doubles = for (i <- ints) yield i * 2
val doubles = for (i <- ints) yield (i * 2)
val doubles = for { i <- ints } yield (i * 2)
val doubles = for i <- ints yield i * 2 // style shown above
val doubles = for (i <- ints) yield i * 2
val doubles = for (i <- ints) yield (i * 2)
val doubles = for { i <- ints } yield (i * 2)
此示例展示了如何将列表中每个字符串的第一个字符大写
val names = List("chris", "ed", "maurice")
val capNames = for (name <- names) yield name.capitalize
val names = List("chris", "ed", "maurice")
val capNames = for name <- names yield name.capitalize
最后,此 for 表达式迭代一个字符串列表,并返回每个字符串的长度,但仅当该长度大于 4 时
val fruits = List("apple", "banana", "lime", "orange")
val fruitLengths =
for (f <- fruits if f.length > 4) yield f.length
// fruitLengths: List[Int] = List(5, 6, 6)
val fruits = List("apple", "banana", "lime", "orange")
val fruitLengths = for
f <- fruits
if f.length > 4
yield
// you can use multiple lines
// of code here
f.length
// fruitLengths: List[Int] = List(5, 6, 6)
for 循环和表达式在本手册的 控制结构部分 和 参考文档 中有更详细的介绍。
match 表达式
Scala 具有一个 match 表达式,在最基本的使用中,它类似于 Java 中的 switch 语句
val i = 1
// later in the code ...
i match {
case 1 => println("one")
case 2 => println("two")
case _ => println("other")
}
val i = 1
// later in the code ...
i match
case 1 => println("one")
case 2 => println("two")
case _ => println("other")
但是,match 实际上是一个表达式,这意味着它会根据模式匹配返回一个结果,你可以将其绑定到一个变量
val result = i match {
case 1 => "one"
case 2 => "two"
case _ => "other"
}
val result = i match
case 1 => "one"
case 2 => "two"
case _ => "other"
match 不仅限于处理整数值,它可以用于任何数据类型
val p = Person("Fred")
// later in the code
p match {
case Person(name) if name == "Fred" =>
println(s"$name says, Yubba dubba doo")
case Person(name) if name == "Bam Bam" =>
println(s"$name says, Bam bam!")
case _ => println("Watch the Flintstones!")
}
val p = Person("Fred")
// later in the code
p match
case Person(name) if name == "Fred" =>
println(s"$name says, Yubba dubba doo")
case Person(name) if name == "Bam Bam" =>
println(s"$name says, Bam bam!")
case _ => println("Watch the Flintstones!")
事实上,match 表达式可用于针对多种不同类型的模式测试变量。此示例展示了 (a) 如何将 match 表达式用作方法的主体,以及 (b) 如何匹配显示的所有不同类型
// getClassAsString is a method that takes a single argument of any type.
def getClassAsString(x: Any): String = x match {
case s: String => s"'$s' is a String"
case i: Int => "Int"
case d: Double => "Double"
case l: List[_] => "List"
case _ => "Unknown"
}
// examples
getClassAsString(1) // Int
getClassAsString("hello") // 'hello' is a String
getClassAsString(List(1, 2, 3)) // List
因为方法 getClassAsString 接受类型为 Any 的参数值,所以它可以被任何类型的模式分解。
// getClassAsString is a method that takes a single argument of any type.
def getClassAsString(x: Matchable): String = x match
case s: String => s"'$s' is a String"
case i: Int => "Int"
case d: Double => "Double"
case l: List[?] => "List"
case _ => "Unknown"
// examples
getClassAsString(1) // Int
getClassAsString("hello") // 'hello' is a String
getClassAsString(List(1, 2, 3)) // List
方法 getClassAsString 将类型为 Matchable 的值作为参数,它可以是支持模式匹配的任何类型(某些类型不支持模式匹配,因为这可能会破坏封装)。
Scala 中的模式匹配还有很多内容。模式可以嵌套,模式的结果可以绑定,甚至可以自定义模式匹配。有关更多详细信息,请参阅 控制结构 章节中的模式匹配示例。
try/catch/finally
Scala 的 try/catch/finally 控制结构允许你捕获异常。它类似于 Java,但其语法与 match 表达式一致
try {
writeTextToFile(text)
} catch {
case ioe: IOException => println("Got an IOException.")
case nfe: NumberFormatException => println("Got a NumberFormatException.")
} finally {
println("Clean up your resources here.")
}
try
writeTextToFile(text)
catch
case ioe: IOException => println("Got an IOException.")
case nfe: NumberFormatException => println("Got a NumberFormatException.")
finally
println("Clean up your resources here.")
while 循环
Scala 还有一个 while 循环结构。它的一行语法如下所示
while (x >= 0) { x = f(x) }
while x >= 0 do x = f(x)
为了兼容性,Scala 3 仍支持 Scala 2 语法。
while 循环的多行语法如下所示
var x = 1
while (x < 3) {
println(x)
x += 1
}
var x = 1
while
x < 3
do
println(x)
x += 1
自定义控制结构
借助按名称参数、中缀表示法、流畅接口、可选括号、扩展方法和高阶函数等特性,你还可以创建自己的代码,其工作方式就像控制结构一样。你将在 控制结构 部分中了解更多相关内容。