Scala 3 — Book

控制结构

Language

Scala具有您希望在编程语言中找到的控制结构，包括：

• `if`/`then`/`else`
• `for` 循环
• `while` 循环
• `try`/`catch`/`finally`

• `for` 表达式（也被称作 `for` comprehensions
• `match` 表达式

if/then/else 结构

``````if (x == 1) println(x)
``````
``````if x == 1 then println(x)
``````

``````if (x == 1) {
println("x is 1, as you can see:")
println(x)
}
``````
``````if x == 1 then
println("x is 1, as you can see:")
println(x)
``````

`if`/`else` 语法像这样：

``````if (x == 1) {
println("x is 1, as you can see:")
println(x)
} else {
println("x was not 1")
}
``````
``````if x == 1 then
println("x is 1, as you can see:")
println(x)
else
println("x was not 1")
``````

``````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")
``````

`end if` 语句

这是 Scala 3 里的新东西，在 Scala 2 里不支持。

``````if x == 1 then
println("x is 1, as you can see:")
println(x)
end if
``````

`if`/`else` 表达式总是有返回值

``````val minValue = if (a < b) a else b
``````
``````val minValue = if a < b then a else b
``````

``````def compare(a: Int, b: Int): Int =
if (a < b)
-1
else if (a == b)
0
else
1
``````
``````def compare(a: Int, b: Int): Int =
if a < b then
-1
else if a == b then
0
else
1
``````

题外话：面向表达式的编程

``````val minValue = if (a < b) a else b
``````
``````val minValue = if a < b then a else b
``````

``````if (a == b) action()
println("Hello")
``````
``````if a == b then action()
println("Hello")
``````

`for` 循环

``````val ints = Seq(1, 2, 3)
for (i <- ints) println(i)
``````
``````val ints = Seq(1, 2, 3)
for i <- ints do println(i)
``````

``````scala> val ints = Seq(1,2,3)
ints: Seq[Int] = List(1, 2, 3)

scala> for (i <- ints) println(i)
1
2
3
``````
``````scala> val ints = Seq(1,2,3)
ints: Seq[Int] = List(1, 2, 3)

scala> for i <- ints do println(i)
1
2
3
``````

``````for (i <- ints) {
val x = i * 2
println(s"i = \$i, x = \$x")
}
``````
``````for
i <- ints
do
val x = i * 2
println(s"i = \$i, x = \$x")
``````

多生成器

`for` 循环可以有多个生成器，如以下示例所示：

``````for {
i <- 1 to 2
j <- 'a' to 'b'
k <- 1 to 10 by 5
} {
println(s"i = \$i, j = \$j, k = \$k")
}
``````
``````for
i <- 1 to 2
j <- 'a' to 'b'
k <- 1 to 10 by 5
do
println(s"i = \$i, j = \$j, k = \$k")
``````

``````i = 1, j = a, k = 1
i = 1, j = a, k = 6
i = 1, j = b, k = 1
i = 1, j = b, k = 6
i = 2, j = a, k = 1
i = 2, j = a, k = 6
i = 2, j = b, k = 1
i = 2, j = b, k = 6
``````

守卫

`for` 循环也可以包含 `if` 语句，这些语句称为 守卫

``````for {
i <- 1 to 5
if i % 2 == 0
} {
println(i)
}
``````
``````for
i <- 1 to 5
if i % 2 == 0
do
println(i)
``````

``````2
4
``````

`for` 循环可以根据需要有任意数量的守卫。 此示例显示了打印数字`4`的一种方法：

``````for {
i <- 1 to 10
if i > 3
if i < 6
if i % 2 == 0
} {
println(i)
}
``````
``````for
i <- 1 to 10
if i > 3
if i < 6
if i % 2 == 0
do
println(i)
``````

把 `for` 用在 `Map` 上

``````val states = Map(
"AL" -> "Alabama",
"AR" -> "Arizona"
)
``````

``````for ((abbrev, fullName) <- states) println(s"\$abbrev: \$fullName")
``````
``````for (abbrev, fullName) <- states do println(s"\$abbrev: \$fullName")
``````

``````scala> for ((abbrev, fullName) <- states) println(s"\$abbrev: \$fullName")
AL: Alabama
AR: Arizona
``````
``````scala> for (abbrev, fullName) <- states do println(s"\$abbrev: \$fullName")
AL: Alabama
AR: Arizona
``````

`for` 循环遍历映射时，每个键/值对都绑定到变量 `abbrev``fullName` ，它们位于元组中：

``````(abbrev, fullName) <- states
``````

`for` 表达式

``````val list =
for (i <- 10 to 12)
yield i * 2

// list: IndexedSeq[Int] = Vector(20, 22, 24)
``````
``````val list =
for i <- 10 to 12
yield i * 2

// list: IndexedSeq[Int] = Vector(20, 22, 24)
``````

`for` 表达式运行后，变量 `list` 是包含所示值的 `Vector` 。 这是表达式的工作原理：

1. `for` 表达式开始循环访问范围 `(10, 11, 12)` 中的值。 它首先处理值`10`，将其乘以`2`，然后 产生 结果为`20`的值。
2. 接下来，它处理`11`—该范围中的第二个值。 它乘以`2`，然后产生值`22`。 您可以将这些产生的值看作它们累积在某个临时位置。
3. 最后，循环从范围中获取数字 `12`，将其乘以 `2`，得到数字 `24`。 循环此时完成并产生最终结果 `Vector(20, 22, 24)`

``````val list = (10 to 12).map(i => i * 2)
``````

``````val names = List("_olivia", "_walter", "_peter")

val capNames = for (name <- names) yield {
val nameWithoutUnderscore = name.drop(1)
val capName = nameWithoutUnderscore.capitalize
capName
}

// capNames: List[String] = List(Olivia, Walter, Peter)
``````
``````val names = List("_olivia", "_walter", "_peter")

val capNames = for name <- names yield
val nameWithoutUnderscore = name.drop(1)
val capName = nameWithoutUnderscore.capitalize
capName

// capNames: List[String] = List(Olivia, Walter, Peter)
``````

使用 `for` 表达式作为方法的主体

``````def between3and10(xs: List[Int]): List[Int] =
for {
x <- xs
if x >= 3
if x <= 10
} yield x

between3and10(List(1, 3, 7, 11))   // : List[Int] = List(3, 7)
``````
``````def between3and10(xs: List[Int]): List[Int] =
for
x <- xs
if x >= 3
if x <= 10
yield x

between3and10(List(1, 3, 7, 11))   // : List[Int] = List(3, 7)
``````

`while` 循环

Scala `while` 循环语法如下：

``````var i = 0

while (i < 3) {
println(i)
i += 1
}
``````
``````var i = 0

while i < 3 do
println(i)
i += 1
``````

`match` 表达式

``````// `i` is an integer
val day = i match {
case 0 => "Sunday"
case 1 => "Monday"
case 2 => "Tuesday"
case 3 => "Wednesday"
case 4 => "Thursday"
case 5 => "Friday"
case 6 => "Saturday"
case _ => "invalid day"   // the default, catch-all
}
``````
``````import scala.annotation.switch

// `i` is an integer
val day = i match
case 0 => "Sunday"
case 1 => "Monday"
case 2 => "Tuesday"
case 3 => "Wednesday"
case 4 => "Thursday"
case 5 => "Friday"
case 6 => "Saturday"
case _ => "invalid day"   // the default, catch-all
``````

使用缺省值

``````i match {
case 0 => println("1")
case 1 => println("2")
case what => println(s"You gave me: \$what")
}
``````
``````i match
case 0 => println("1")
case 1 => println("2")
case what => println(s"You gave me: \$what" )
``````

``````val N = 42
i match {
case 0 => println("1")
case 1 => println("2")
case N => println("42")
case n => println(s"You gave me: \$n" )
}
``````
``````val N = 42
i match
case 0 => println("1")
case 1 => println("2")
case N => println("42")
case n => println(s"You gave me: \$n" )
``````

在一行上处理多个可能的匹配项

``````val evenOrOdd = i match {
case 1 | 3 | 5 | 7 | 9 => println("odd")
case 2 | 4 | 6 | 8 | 10 => println("even")
case _ => println("some other number")
}
``````
``````val evenOrOdd = i match
case 1 | 3 | 5 | 7 | 9 => println("odd")
case 2 | 4 | 6 | 8 | 10 => println("even")
case _ => println("some other number")
``````

在 `case` 子句中使用 `if` 守卫

``````i match {
case 1 => println("one, a lonely number")
case x if x == 2 || x == 3 => println("two’s company, three’s a crowd")
case x if x > 3 => println("4+, that’s a party")
case _ => println("i’m guessing your number is zero or less")
}
``````
``````i match
case 1 => println("one, a lonely number")
case x if x == 2 || x == 3 => println("two’s company, three’s a crowd")
case x if x > 3 => println("4+, that’s a party")
case _ => println("i’m guessing your number is zero or less")
``````

``````i match {
case a if 0 to 9 contains a => println(s"0-9 range: \$a")
case b if 10 to 19 contains b => println(s"10-19 range: \$b")
case c if 20 to 29 contains c => println(s"20-29 range: \$c")
case _ => println("Hmmm...")
}
``````
``````i match
case a if 0 to 9 contains a => println(s"0-9 range: \$a")
case b if 10 to 19 contains b => println(s"10-19 range: \$b")
case c if 20 to 29 contains c => println(s"20-29 range: \$c")
case _ => println("Hmmm...")
``````

样例类和 match 表达式

``````case class Person(name: String)

def speak(p: Person) = 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!")
}

speak(Person("Fred"))      // "Fred says, Yubba dubba doo"
speak(Person("Bam Bam"))   // "Bam Bam says, Bam bam!"
``````
``````case class Person(name: String)

def speak(p: Person) = 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!")

speak(Person("Fred"))      // "Fred says, Yubba dubba doo"
speak(Person("Bam Bam"))   // "Bam Bam says, Bam bam!"
``````

使用 `match` 表达式作为方法的主体

``````def isTruthy(a: Matchable) = a match {
case 0 | "" | false => false
case _              => true
}
``````
``````def isTruthy(a: Matchable) = a match
case 0 | "" | false => false
case _              => true
``````

``````isTruthy(0)      // false
isTruthy(false)  // false
isTruthy("")     // false
isTruthy(1)      // true
isTruthy(" ")    // true
isTruthy(2F)     // true
``````

匹配表达式支持许多不同类型的模式

• 常量模式（如 `case 3 => `
• 序列模式（如 `case List(els : _*) =>`
• 元组模式（如 `case (x, y) =>`
• 构造函数模式（如 `case Person(first, last) =>`
• 类型测试模式（如 `case p: Person =>`

``````def pattern(x: Matchable): String = x match {

// constant patterns
case 0 => "zero"
case true => "true"
case "hello" => "you said 'hello'"
case Nil => "an empty List"

// sequence patterns
case List(0, _, _) => "a 3-element list with 0 as the first element"
case List(1, _*) => "list, starts with 1, has any number of elements"
case Vector(1, _*) => "vector, starts w/ 1, has any number of elements"

// tuple patterns
case (a, b) => s"got \$a and \$b"
case (a, b, c) => s"got \$a, \$b, and \$c"

// constructor patterns
case Person(first, "Alexander") => s"Alexander, first name = \$first"
case Dog("Zeus") => "found a dog named Zeus"

// type test patterns
case s: String => s"got a string: \$s"
case i: Int => s"got an int: \$i"
case f: Float => s"got a float: \$f"
case a: Array[Int] => s"array of int: \${a.mkString(",")}"
case as: Array[String] => s"string array: \${as.mkString(",")}"
case d: Dog => s"dog: \${d.name}"
case list: List[?] => s"got a List: \$list"
case m: Map[?, ?] => m.toString

// the default wildcard pattern
case _ => "Unknown"
}
``````
``````def pattern(x: Matchable): String = x match

// constant patterns
case 0 => "zero"
case true => "true"
case "hello" => "you said 'hello'"
case Nil => "an empty List"

// sequence patterns
case List(0, _, _) => "a 3-element list with 0 as the first element"
case List(1, _*) => "list, starts with 1, has any number of elements"
case Vector(1, _*) => "vector, starts w/ 1, has any number of elements"

// tuple patterns
case (a, b) => s"got \$a and \$b"
case (a, b, c) => s"got \$a, \$b, and \$c"

// constructor patterns
case Person(first, "Alexander") => s"Alexander, first name = \$first"
case Dog("Zeus") => "found a dog named Zeus"

// type test patterns
case s: String => s"got a string: \$s"
case i: Int => s"got an int: \$i"
case f: Float => s"got a float: \$f"
case a: Array[Int] => s"array of int: \${a.mkString(",")}"
case as: Array[String] => s"string array: \${as.mkString(",")}"
case d: Dog => s"dog: \${d.name}"
case list: List[?] => s"got a List: \$list"
case m: Map[?, ?] => m.toString

// the default wildcard pattern
case _ => "Unknown"
``````

try/catch/finally

``````var text = ""
try {
} catch {
case fnf: FileNotFoundException => fnf.printStackTrace()
case ioe: IOException => ioe.printStackTrace()
} finally {
println("Came to the 'finally' clause.")
}
``````
``````var text = ""
try