update chapter 'control flow' to swift 3
This commit is contained in:
@ -14,7 +14,11 @@
|
|||||||
|
|
||||||
> 2.2
|
> 2.2
|
||||||
> 翻译:[LinusLing](https://github.com/linusling)
|
> 翻译:[LinusLing](https://github.com/linusling)
|
||||||
> 校对:[SketchK](https://github.com/SketchK) 2016-05-12
|
> 校对:[SketchK](https://github.com/SketchK)
|
||||||
|
|
||||||
|
> 3.0
|
||||||
|
> 翻译:[Realank](https://github.com/realank) 2016-09-13
|
||||||
|
|
||||||
|
|
||||||
本页包含内容:
|
本页包含内容:
|
||||||
|
|
||||||
@ -25,16 +29,16 @@
|
|||||||
- [提前退出](#early_exit)
|
- [提前退出](#early_exit)
|
||||||
- [检测 API 可用性](#checking_api_availability)
|
- [检测 API 可用性](#checking_api_availability)
|
||||||
|
|
||||||
Swift提供了多种流程控制结构,包括可以多次执行任务的`while`循环,基于特定条件选择执行不同代码分支的`if`、`guard`和`switch`语句,还有控制流程跳转到其他代码的`break`和`continue`语句。
|
Swift提供了多种流程控制结构,包括可以多次执行任务的`while`循环,基于特定条件选择执行不同代码分支的`if`、`guard`和`switch`语句,还有控制流程跳转到其他代码位置的`break`和`continue`语句。
|
||||||
|
|
||||||
Swift 还增加了`for-in`循环,用来更简单地遍历数组(array),字典(dictionary),区间(range),字符串(string)和其他序列类型。
|
Swift 还提供了`for-in`循环,用来更简单地遍历数组(array),字典(dictionary),区间(range),字符串(string)和其他序列类型。
|
||||||
|
|
||||||
Swift 的`switch`语句比 C 语言中更加强大。在 C 语言中,如果某个 case 不小心漏写了`break`,这个 case 就会贯穿至下一个 case,Swift 无需写`break`,所以不会发生这种贯穿的情况。case 还可以匹配更多的类型模式,包括区间匹配(range matching),元组(tuple)和特定类型的描述。`switch`的 case 语句中匹配的值可以是由 case 体内部临时的常量或者变量决定,也可以由`where`分句描述更复杂的匹配条件。
|
Swift 的`switch`语句比 C 语言中更加强大。在 C 语言中,如果某个 case 不小心漏写了`break`,这个 case 就会贯穿至下一个 case,Swift 无需写`break`,所以不会发生这种贯穿的情况。case 还可以匹配很多不同的模式,包括间隔匹配(interval match),元组(tuple)和转换到特定类型。`switch`语句的 case 中匹配的值可以绑定成临时常量或变量,在case体内使用,也可以用`where`来描述更复杂的匹配条件。
|
||||||
|
|
||||||
<a name="for_in_loops"></a>
|
<a name="for_in_loops"></a>
|
||||||
## For-In 循环
|
## For-In 循环
|
||||||
|
|
||||||
你可以使用`for-in`循环来遍历一个集合里面的所有元素,例如由数字表示的区间、数组中的元素、字符串中的字符。
|
你可以使用`for-in`循环来遍历一个集合中的所有元素,例如数字范围、数组中的元素或者字符串中的字符。
|
||||||
|
|
||||||
下面的例子用来输出乘 5 乘法表前面一部分内容:
|
下面的例子用来输出乘 5 乘法表前面一部分内容:
|
||||||
|
|
||||||
@ -49,11 +53,11 @@ for index in 1...5 {
|
|||||||
// 5 times 5 is 25
|
// 5 times 5 is 25
|
||||||
```
|
```
|
||||||
|
|
||||||
例子中用来进行遍历的元素是一组使用闭区间操作符(`...`)表示的从`1`到`5`的数字。`index`被赋值为闭区间中的第一个数字(`1`),然后循环中的语句被执行一次。在本例中,这个循环只包含一个语句,用来输出当前`index`值所对应的乘 5 乘法表结果。该语句执行后,`index`的值被更新为闭区间中的第二个数字(`2`),之后`print(_:separator:terminator:)`函数会再执行一次。整个过程会进行到闭区间结尾为止。
|
例子中用来进行遍历的元素是使用闭区间操作符(`...`)表示的从`1`到`5`的数字区间。`index`被赋值为闭区间中的第一个数字(`1`),然后循环中的语句被执行一次。在本例中,这个循环只包含一个语句,用来输出当前`index`值所对应的乘 5 乘法表的结果。该语句执行后,`index`的值被更新为闭区间中的第二个数字(`2`),之后`print(_:separator:terminator:)`函数会再执行一次。整个过程会进行到闭区间结尾为止。
|
||||||
|
|
||||||
上面的例子中,`index`是一个每次循环遍历开始时被自动赋值的常量。这种情况下,`index`在使用前不需要声明,只需要将它包含在循环的声明中,就可以对其进行隐式声明,而无需使用`let`关键字声明。
|
上面的例子中,`index`是一个每次循环遍历开始时被自动赋值的常量。这种情况下,`index`在使用前不需要声明,只需要将它包含在循环的声明中,就可以对其进行隐式声明,而无需使用`let`关键字声明。
|
||||||
|
|
||||||
如果你不需要知道区间序列内每一项的值,你可以使用下划线(`_`)替代变量名来忽略对值的访问:
|
如果你不需要区间序列内每一项的值,你可以使用下划线(`_`)替代变量名来忽略这个值:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let base = 3
|
let base = 3
|
||||||
@ -66,7 +70,7 @@ print("\(base) to the power of \(power) is \(answer)")
|
|||||||
// 输出 "3 to the power of 10 is 59049"
|
// 输出 "3 to the power of 10 is 59049"
|
||||||
```
|
```
|
||||||
|
|
||||||
这个例子计算 base 这个数的 power 次幂(本例中,是`3`的`10`次幂),从`1`(`3`的`0`次幂)开始做`3`的乘法, 进行`10`次,使用`1`到`10`的闭区间循环。这个计算并不需要知道每一次循环中计数器具体的值,只需要执行了正确的循环次数即可。下划线符号`_`(替代循环中的变量)能够忽略具体的值,并且不提供循环遍历时对值的访问。
|
这个例子计算 base 这个数的 power 次幂(本例中,是`3`的`10`次幂),从`1`(`3`的`0`次幂)开始做`3`的乘法, 进行`10`次,使用`1`到`10`的闭区间循环。这个计算并不需要知道每一次循环中计数器具体的值,只需要执行了正确的循环次数即可。下划线符号`_`(替代循环中的变量)能够忽略当前值,并且不提供循环遍历时对值的访问。
|
||||||
|
|
||||||
使用`for-in`遍历一个数组所有元素:
|
使用`for-in`遍历一个数组所有元素:
|
||||||
|
|
||||||
@ -98,7 +102,7 @@ for (animalName, legCount) in numberOfLegs {
|
|||||||
<a name="while_loops"></a>
|
<a name="while_loops"></a>
|
||||||
## While 循环
|
## While 循环
|
||||||
|
|
||||||
`while`循环运行一系列语句直到条件变成`false`。这类循环适合使用在第一次迭代前迭代次数未知的情况下。Swift 提供两种`while`循环形式:
|
`while`循环会一直运行一段语句直到条件变成`false`。这类循环适合使用在第一次迭代前,迭代次数未知的情况下。Swift 提供两种`while`循环形式:
|
||||||
|
|
||||||
* `while`循环,每次在循环开始时计算条件是否符合;
|
* `while`循环,每次在循环开始时计算条件是否符合;
|
||||||
* `repeat-while`循环,每次在循环结束时计算条件是否符合。
|
* `repeat-while`循环,每次在循环结束时计算条件是否符合。
|
||||||
@ -106,11 +110,11 @@ for (animalName, legCount) in numberOfLegs {
|
|||||||
<a name="while"></a>
|
<a name="while"></a>
|
||||||
###While
|
###While
|
||||||
|
|
||||||
`while`循环从计算单一条件开始。如果条件为`true`,会重复运行一系列语句,直到条件变为`false`。
|
`while`循环从计算一个条件开始。如果条件为`true`,会重复运行一段语句,直到条件变为`false`。
|
||||||
|
|
||||||
下面是一般情况下 `while` 循环格式:
|
下面是 `while` 循环的一般格式:
|
||||||
|
|
||||||
```swift
|
```
|
||||||
while condition {
|
while condition {
|
||||||
statements
|
statements
|
||||||
}
|
}
|
||||||
@ -123,7 +127,7 @@ while condition {
|
|||||||
游戏的规则如下:
|
游戏的规则如下:
|
||||||
|
|
||||||
* 游戏盘面包括 25 个方格,游戏目标是达到或者超过第 25 个方格;
|
* 游戏盘面包括 25 个方格,游戏目标是达到或者超过第 25 个方格;
|
||||||
* 每一轮,你通过掷一个 6 边的骰子来确定你移动方块的步数,移动的路线由上图中横向的虚线所示;
|
* 每一轮,你通过掷一个六面体骰子来确定你移动方块的步数,移动的路线由上图中横向的虚线所示;
|
||||||
* 如果在某轮结束,你移动到了梯子的底部,可以顺着梯子爬上去;
|
* 如果在某轮结束,你移动到了梯子的底部,可以顺着梯子爬上去;
|
||||||
* 如果在某轮结束,你移动到了蛇的头部,你会顺着蛇的身体滑下去。
|
* 如果在某轮结束,你移动到了蛇的头部,你会顺着蛇的身体滑下去。
|
||||||
|
|
||||||
@ -131,19 +135,19 @@ while condition {
|
|||||||
|
|
||||||
```swift
|
```swift
|
||||||
let finalSquare = 25
|
let finalSquare = 25
|
||||||
var board = [Int](count: finalSquare + 1, repeatedValue: 0)
|
var board = [Int](repeating: 0, count: finalSquare + 1)
|
||||||
```
|
```
|
||||||
|
|
||||||
一些方块被设置成有蛇或者梯子的指定值。梯子底部的方块是一个正值,使你可以向上移动,蛇头处的方块是一个负值,会让你向下移动:
|
一些方格被设置成特定的值来表示有蛇或者梯子。梯子底部的方格是一个正值,使你可以向上移动,蛇头处的方格是一个负值,会让你向下移动:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
|
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
|
||||||
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
|
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
|
||||||
```
|
```
|
||||||
|
|
||||||
3 号方块是梯子的底部,会让你向上移动到 11 号方格,我们使用`board[03]`等于`+08`(来表示`11`和`3`之间的差值)。使用一元加运算符(`+i`)是为了和一元减运算符(`-i`)对称,为了让盘面代码整齐,小于 10 的数字都使用 0 补齐(这些风格上的调整都不是必须的,只是为了让代码看起来更加整洁)。
|
3 号方格是梯子的底部,会让你向上移动到 11 号方格,我们使用`board[03]`等于`+08`(来表示`11`和`3`之间的差值)。使用一元正运算符(`+i`)是为了和一元负运算符(`-i`)对称,为了让盘面代码整齐,小于 10 的数字都使用 0 补齐(这些风格上的调整都不是必须的,只是为了让代码看起来更加整洁)。
|
||||||
|
|
||||||
玩家由左下角编号为 0 的方格开始游戏。一般来说玩家第一次掷骰子后才会进入游戏盘面:
|
玩家由左下角空白处编号为 0 的方格开始游戏。玩家第一次掷骰子后才会进入游戏盘面:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var square = 0
|
var square = 0
|
||||||
@ -162,27 +166,27 @@ while square < finalSquare {
|
|||||||
print("Game over!")
|
print("Game over!")
|
||||||
```
|
```
|
||||||
|
|
||||||
本例中使用了最简单的方法来模拟掷骰子。 `diceRoll`的值并不是一个随机数,而是以`0`为初始值,之后每一次`while`循环,`diceRoll`的值增加 1 ,然后检测是否超出了最大值。任何时候如果`diceRoll`的值等于 7 时,就超过了骰子的最大值,会被重置为`1`。所以`diceRoll`的取值顺序会一直是`1`。因此,`diceRoll` 所有的值只可能是 `1` ,`2`,`3`,`4`,`5`,`6`,`1`,`2` 等。
|
本例中使用了最简单的方法来模拟掷骰子。 `diceRoll`的值并不是一个随机数,而是以`0`为初始值,之后每一次`while`循环,`diceRoll`的值增加 1 ,然后检测是否超出了最大值。当`diceRoll`的值等于 7 时,就超过了骰子的最大值,会被重置为`1`。所以`diceRoll`的取值顺序会一直是 `1` ,`2`,`3`,`4`,`5`,`6`,`1`,`2` 等。
|
||||||
|
|
||||||
掷完骰子后,玩家向前移动`diceRoll`个方格,如果玩家移动超过了第 25 个方格,这个时候游戏结束,相应地,代码会在`square`增加`board[square]`的值向前或向后移动(遇到了梯子或者蛇)之前,检测`square`的值是否小于`board`的`count`属性。
|
掷完骰子后,玩家向前移动`diceRoll`个方格,如果玩家移动超过了第 25 个方格,这个时候游戏将会结束,为了应对这种情况,代码会首先判断`square`的值是否小于`board`的`count`属性,只有小于才会在`board[square]`上增加`square`,来向前或向后移动(遇到了梯子或者蛇)。
|
||||||
|
|
||||||
> 注意:
|
> 注意:
|
||||||
> 如果没有这个检测(`square < board.count`),`board[square]`可能会越界访问`board`数组,导致错误。例如如果`square`等于`26`, 代码会去尝试访问`board[26]`,超过数组的长度。
|
> 如果没有这个检测(`square < board.count`),`board[square]`可能会越界访问`board`数组,导致错误。如果`square`等于`26`, 代码会去尝试访问`board[26]`,超过数组的长度。
|
||||||
|
|
||||||
当本轮`while`循环运行完毕,会再检测循环条件是否需要再运行一次循环。如果玩家移动到或者超过第 25 个方格,循环条件结果为`false`,此时游戏结束。
|
当本轮`while`循环运行完毕,会再检测循环条件是否需要再运行一次循环。如果玩家移动到或者超过第 25 个方格,循环条件结果为`false`,此时游戏结束。
|
||||||
|
|
||||||
`while` 循环比较适合本例中的这种情况,因为在 `while` 循环开始时,我们并不知道游戏的长度或者循环的次数,只有在达成指定条件时循环才会结束。
|
`while` 循环比较适合本例中的这种情况,因为在 `while` 循环开始时,我们并不知道游戏要跑多久,只有在达成指定条件时循环才会结束。
|
||||||
|
|
||||||
|
|
||||||
<a name="repeat_while"></a>
|
<a name="repeat_while"></a>
|
||||||
###Repeat-While
|
###Repeat-While
|
||||||
|
|
||||||
`while`循环的另外一种形式是`repeat-while`,它和`while`的区别是在判断循环条件之前,先执行一次循环的代码块,然后重复循环直到条件为`false`。
|
`while`循环的另外一种形式是`repeat-while`,它和`while`的区别是在判断循环条件之前,先执行一次循环的代码块。然后重复循环直到条件为`false`。
|
||||||
|
|
||||||
> 注意:
|
> 注意:
|
||||||
> Swift语言的`repeat-while`循环合其他语言中的`do-while`循环是类似的。
|
> Swift语言的`repeat-while`循环和其他语言中的`do-while`循环是类似的。
|
||||||
|
|
||||||
下面是一般情况下 `repeat-while`循环的格式:
|
下面是 `repeat-while`循环的一般格式:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
repeat {
|
repeat {
|
||||||
@ -190,11 +194,11 @@ repeat {
|
|||||||
} while condition
|
} while condition
|
||||||
```
|
```
|
||||||
|
|
||||||
还是蛇和梯子的游戏,使用`repeat-while`循环来替代`while`循环。`finalSquare`、`board`、`square`和`diceRoll`的值初始化同`while`循环一样:
|
还是蛇和梯子的游戏,使用`repeat-while`循环来替代`while`循环。`finalSquare`、`board`、`square`和`diceRoll`的值初始化同`while`循环时一样:
|
||||||
|
|
||||||
``` swift
|
``` swift
|
||||||
let finalSquare = 25
|
let finalSquare = 25
|
||||||
var board = [Int](count: finalSquare + 1, repeatedValue: 0)
|
var board = [Int](repeating: 0, count: finalSquare + 1)
|
||||||
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
|
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
|
||||||
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
|
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
|
||||||
var square = 0
|
var square = 0
|
||||||
@ -225,14 +229,14 @@ print("Game over!")
|
|||||||
<a name="conditional_statement"></a>
|
<a name="conditional_statement"></a>
|
||||||
## 条件语句
|
## 条件语句
|
||||||
|
|
||||||
根据特定的条件执行特定的代码通常是十分有用的,例如:当错误发生时,你可能想运行额外的代码;或者,当输入的值太大或太小时,向用户显示一条消息等。要实现这些功能,你就需要使用*条件语句*。
|
根据特定的条件执行特定的代码通常是十分有用的。当错误发生时,你可能想运行额外的代码;或者,当值太大或太小时,向用户显示一条消息。要实现这些功能,你就需要使用*条件语句*。
|
||||||
|
|
||||||
Swift 提供两种类型的条件语句:`if`语句和`switch`语句。通常,当条件较为简单且可能的情况很少时,使用`if`语句。而`switch`语句更适用于条件较复杂、可能情况较多且需要用到模式匹配(pattern-matching)的情境。
|
Swift 提供两种类型的条件语句:`if`语句和`switch`语句。通常,当条件较为简单且可能的情况很少时,使用`if`语句。而`switch`语句更适用于条件较复杂、有更多排列组合的时候。并且`switch`在需要用到模式匹配(pattern-matching)的情况下会更有用。
|
||||||
|
|
||||||
<a name="if"></a>
|
<a name="if"></a>
|
||||||
### If
|
### If
|
||||||
|
|
||||||
`if`语句最简单的形式就是只包含一个条件,当且仅当该条件为`true`时,才执行相关代码:
|
`if`语句最简单的形式就是只包含一个条件,只有该条件为`true`时,才执行相关代码:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var temperatureInFahrenheit = 30
|
var temperatureInFahrenheit = 30
|
||||||
@ -244,7 +248,7 @@ if temperatureInFahrenheit <= 32 {
|
|||||||
|
|
||||||
上面的例子会判断温度是否小于等于 32 华氏度(水的冰点)。如果是,则打印一条消息;否则,不打印任何消息,继续执行`if`块后面的代码。
|
上面的例子会判断温度是否小于等于 32 华氏度(水的冰点)。如果是,则打印一条消息;否则,不打印任何消息,继续执行`if`块后面的代码。
|
||||||
|
|
||||||
当然,`if`语句允许二选一,也就是当条件为`false`时,执行 *else 语句*:
|
当然,`if`语句允许二选一执行,叫做`else`从句。也就是当条件为`false`时,执行 *else 语句*:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
temperatureInFahrenheit = 40
|
temperatureInFahrenheit = 40
|
||||||
@ -256,9 +260,9 @@ if temperatureInFahrenheit <= 32 {
|
|||||||
// 输出 "It's not that cold. Wear a t-shirt."
|
// 输出 "It's not that cold. Wear a t-shirt."
|
||||||
```
|
```
|
||||||
|
|
||||||
显然,这两条分支中总有一条会被执行。由于温度已升至 40 华氏度,不算太冷,没必要再围围巾——因此,`else`分支就被触发了。
|
显然,这两条分支中总有一条会被执行。由于温度已升至 40 华氏度,不算太冷,没必要再围围巾。因此,`else`分支就被触发了。
|
||||||
|
|
||||||
你可以把多个`if`语句链接在一起,像下面这样:
|
你可以把多个`if`语句链接在一起,来实现更多分支:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
temperatureInFahrenheit = 90
|
temperatureInFahrenheit = 90
|
||||||
@ -274,7 +278,7 @@ if temperatureInFahrenheit <= 32 {
|
|||||||
|
|
||||||
在上面的例子中,额外的`if`语句用于判断是不是特别热。而最后的`else`语句被保留了下来,用于打印既不冷也不热时的消息。
|
在上面的例子中,额外的`if`语句用于判断是不是特别热。而最后的`else`语句被保留了下来,用于打印既不冷也不热时的消息。
|
||||||
|
|
||||||
实际上,最后的`else`语句是可选的:
|
实际上,当不需要完整判断情况的时候,最后的`else`语句是可选的:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
temperatureInFahrenheit = 72
|
temperatureInFahrenheit = 72
|
||||||
@ -306,36 +310,37 @@ default:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`switch`语句都由*多个 case* 构成。为了匹配某些更特定的值,Swift 提供了几种更复杂的匹配模式,这些模式将在本节的稍后部分提到。
|
|
||||||
|
|
||||||
每一个 case 都是代码执行的一条分支,这与`if`语句类似。与之不同的是,`switch`语句会决定哪一条分支应该被执行。
|
`switch`语句由*多个 case* 构成,每个由`case`关键字开始。为了匹配某些更特定的值,Swift 提供了几种方法来进行更复杂的模式匹配,这些模式将在本节的稍后部分提到。
|
||||||
|
|
||||||
`switch`语句必须是完备的。这就是说,每一个可能的值都必须至少有一个 case 分支与之对应。在某些不可能涵盖所有值的情况下,你可以使用默认(`default`)分支满足该要求,这个默认分支必须在`switch`语句的最后面。
|
与`if`语句类似,每一个 case 都是代码执行的一条分支。`switch`语句会决定哪一条分支应该被执行,这个流程被称作根据给定的值*切换(switching)*。
|
||||||
|
|
||||||
|
`switch`语句必须是完备的。这就是说,每一个可能的值都必须至少有一个 case 分支与之对应。在某些不可能涵盖所有值的情况下,你可以使用默认(`default`)分支来涵盖其它所有没有对应的值,这个默认分支必须在`switch`语句的最后面。
|
||||||
|
|
||||||
下面的例子使用`switch`语句来匹配一个名为`someCharacter`的小写字符:
|
下面的例子使用`switch`语句来匹配一个名为`someCharacter`的小写字符:
|
||||||
|
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let someCharacter: Character = "e"
|
let someCharacter: Character = "z"
|
||||||
switch someCharacter {
|
switch someCharacter {
|
||||||
case "a", "e", "i", "o", "u":
|
case "a":
|
||||||
print("\(someCharacter) is a vowel")
|
print("The first letter of the alphabet")
|
||||||
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
|
case "z":
|
||||||
"n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
|
print("The last letter of the alphabet")
|
||||||
print("\(someCharacter) is a consonant")
|
|
||||||
default:
|
default:
|
||||||
print("\(someCharacter) is not a vowel or a consonant")
|
print("Some other character")
|
||||||
}
|
}
|
||||||
// 输出 "e is a vowel"
|
// Prints "The last letter of the alphabet"
|
||||||
```
|
```
|
||||||
|
|
||||||
在这个例子中,第一个 case 分支用于匹配五个元音,第二个 case 分支用于匹配所有的辅音。
|
在这个例子中,第一个 case 分支用于匹配第一个英文字母`a`,第二个 case 分支用于匹配最后一个字母`z`。
|
||||||
|
因为`switch`语句必须有一个case分支用于覆盖所有可能的字符,而不仅仅是所有的英文字母,所以switch语句使用`default`分支来匹配除了`a`和`z`外的所有值,这个分支保证了swith语句的完备性。
|
||||||
|
|
||||||
由于为其它可能的字符写 case 分支没有实际的意义,因此在这个例子中使用了默认分支来处理剩下的既不是元音也不是辅音的字符——这就保证了`switch`语句的完备性。
|
|
||||||
|
|
||||||
<a name="no_implicit_fallthrough"></a>
|
<a name="no_implicit_fallthrough"></a>
|
||||||
#### 不存在隐式的贯穿(No Implicit Fallthrough)
|
#### 不存在隐式的贯穿(No Implicit Fallthrough)
|
||||||
|
|
||||||
与 C 语言和 Objective-C 中的`switch`语句不同,在 Swift 中,当匹配的 case 分支中的代码执行完毕后,程序会终止`switch`语句,而不会继续执行下一个 case 分支。这也就是说,不需要在 case 分支中显式地使用`break`语句。这使得`switch`语句更安全、更易用,也避免了因忘记写`break`语句而产生的错误。
|
与 C 和 Objective-C 中的`switch`语句不同,在 Swift 中,当匹配的 case 分支中的代码执行完毕后,程序会终止`switch`语句,而不会继续执行下一个 case 分支。这也就是说,不需要在 case 分支中显式地使用`break`语句。这使得`switch`语句更安全、更易用,也避免了因忘记写`break`语句而产生的错误。
|
||||||
|
|
||||||
> 注意:
|
> 注意:
|
||||||
虽然在Swift中`break`不是必须的,但你依然可以在 case 分支中的代码执行完毕前使用`break`跳出,详情请参见[Switch 语句中的 break](#break_in_a_switch_statement)。
|
虽然在Swift中`break`不是必须的,但你依然可以在 case 分支中的代码执行完毕前使用`break`跳出,详情请参见[Switch 语句中的 break](#break_in_a_switch_statement)。
|
||||||
@ -345,29 +350,32 @@ default:
|
|||||||
```swift
|
```swift
|
||||||
let anotherCharacter: Character = "a"
|
let anotherCharacter: Character = "a"
|
||||||
switch anotherCharacter {
|
switch anotherCharacter {
|
||||||
case "a":
|
case "a": // Invalid, the case has an empty body
|
||||||
case "A":
|
case "A":
|
||||||
print("The letter A")
|
print("The letter A")
|
||||||
default:
|
default:
|
||||||
print("Not the letter A")
|
print("Not the letter A")
|
||||||
}
|
}
|
||||||
// this will report a compile-time error
|
// This will report a compile-time error.
|
||||||
```
|
```
|
||||||
|
|
||||||
不像 C 语言里的`switch`语句,在 Swift 中,`switch`语句不会同时匹配`"a"`和`"A"`。相反的,上面的代码会引起编译期错误:`case "a": does not contain any executable statements`——这就避免了意外地从一个 case 分支贯穿到另外一个,使得代码更安全、也更直观。
|
不像 C 语言里的`switch`语句,在 Swift 中,`switch`语句不会一起匹配`"a"`和`"A"`。相反的,上面的代码会引起编译期错误:`case "a": 不包含任何可执行语句`——这就避免了意外地从一个 case 分支贯穿到另外一个,使得代码更安全、也更直观。
|
||||||
|
|
||||||
一个 case 也可以包含多个模式,用逗号把它们分开(如果太长了也可以分行写):
|
|
||||||
|
|
||||||
|
为了让单个case同时匹配`a`和`A`,可以将这个两个值组合成一个复合匹配,并且用逗号分开:
|
||||||
```swift
|
```swift
|
||||||
switch some value to consider {
|
let anotherCharacter: Character = "a"
|
||||||
case value 1,
|
switch anotherCharacter {
|
||||||
value 2:
|
case "a", "A":
|
||||||
statements
|
print("The letter A")
|
||||||
|
default:
|
||||||
|
print("Not the letter A")
|
||||||
}
|
}
|
||||||
|
// Prints "The letter A
|
||||||
```
|
```
|
||||||
|
为了可读性,符合匹配可以写成多行形式,详情请参考[复合匹配(Compound Cases)](#compound_cases)
|
||||||
|
|
||||||
> 注意:
|
> 注意:
|
||||||
如果想要贯穿至特定的 case 分支中,请使用`fallthrough`语句,详情请参考[贯穿(Fallthrough)](#fallthrough)。
|
如果想要显式贯穿case分支,请使用`fallthrough`语句,详情请参考[贯穿(Fallthrough)](#fallthrough)。
|
||||||
|
|
||||||
<a name="interval_matching"></a>
|
<a name="interval_matching"></a>
|
||||||
#### 区间匹配
|
#### 区间匹配
|
||||||
@ -396,10 +404,9 @@ print("There are \(naturalCount) \(countedThings).")
|
|||||||
// 输出 "There are dozens of moons orbiting Saturn."
|
// 输出 "There are dozens of moons orbiting Saturn."
|
||||||
```
|
```
|
||||||
|
|
||||||
在上例中,`approximateCount`在一个`switch`声明中被估值。每一个`case`都与之进行比较。因为`approximateCount`落在了 12 到 100 的区间,所以`naturalCount`等于`"dozens of"`值,并且此后这段执行跳出了`switch`声明。
|
在上例中,`approximateCount`在一个`switch`声明中被评估。每一个`case`都与之进行比较。因为`approximateCount`落在了 12 到 100 的区间,所以`naturalCount`等于`"dozens of"`值,并且此后的执行跳出了`switch`语句。
|
||||||
|
|
||||||
|
|
||||||
> 注意:
|
|
||||||
> 闭区间操作符(`...`)以及半开区间操作符(`..<`)功能被重载去返回`IntervalType`或`Range`。一个区间可以决定他是否包含特定的元素,就像当匹配一个`switch`声明的`case`一样。区间是一个连续值的集合,可以用`for-in`语句遍历它。
|
|
||||||
|
|
||||||
<a name="tuples"></a>
|
<a name="tuples"></a>
|
||||||
#### 元组(Tuple)
|
#### 元组(Tuple)
|
||||||
@ -427,15 +434,15 @@ default:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
在上面的例子中,`switch`语句会判断某个点是否是原点(0, 0),是否在红色的x轴上,是否在黄色y轴上,是否在一个以原点为中心的4x4的矩形里,或者在这个矩形外面。
|
在上面的例子中,`switch`语句会判断某个点是否是原点(0, 0),是否在红色的x轴上,是否在橘黄色的y轴上,是否在一个以原点为中心的4x4的蓝色矩形里,或者在这个矩形外面。
|
||||||
|
|
||||||
不像 C 语言,Swift 允许多个 case 匹配同一个值。实际上,在这个例子中,点(0, 0)可以匹配所有_四个 case_。但是,如果存在多个匹配,那么只会执行第一个被匹配到的 case 分支。考虑点(0, 0)会首先匹配`case (0, 0)`,因此剩下的能够匹配(0, 0)的 case 分支都会被忽视掉。
|
不像 C 语言,Swift 允许多个 case 匹配同一个值。实际上,在这个例子中,点(0, 0)可以匹配所有_四个 case_。但是,如果存在多个匹配,那么只会执行第一个被匹配到的 case 分支。考虑点(0, 0)会首先匹配`case (0, 0)`,因此剩下的能够匹配的分支都会被忽视掉。
|
||||||
|
|
||||||
|
|
||||||
<a name="value_bindings"></a>
|
<a name="value_bindings"></a>
|
||||||
#### 值绑定(Value Bindings)
|
#### 值绑定(Value Bindings)
|
||||||
|
|
||||||
case 分支的模式允许将匹配的值绑定到一个临时的常量或变量,这些常量或变量在该 case 分支里就可以被引用了——这种行为被称为*值绑定*(value binding)。
|
case 分支允许将匹配的值绑定到一个临时的常量或变量,并且在case分支体内使用 —— 这种行为被称为*值绑定*(value binding),因为匹配的值在case分支体内,与临时的常量或变量绑定。
|
||||||
|
|
||||||
下面的例子展示了如何在一个`(Int, Int)`类型的元组中使用值绑定来分类下图中的点(x, y):
|
下面的例子展示了如何在一个`(Int, Int)`类型的元组中使用值绑定来分类下图中的点(x, y):
|
||||||
|
|
||||||
@ -454,11 +461,11 @@ case let (x, y):
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
在上面的例子中,`switch`语句会判断某个点是否在红色的x轴上,是否在黄色y轴上,或者不在坐标轴上。
|
在上面的例子中,`switch`语句会判断某个点是否在红色的x轴上,是否在橘黄色的y轴上,或者不在坐标轴上。
|
||||||
|
|
||||||
这三个 case 都声明了常量`x`和`y`的占位符,用于临时获取元组`anotherPoint`的一个或两个值。第一个 case ——`case (let x, 0)`将匹配一个纵坐标为`0`的点,并把这个点的横坐标赋给临时的常量`x`。类似的,第二个 case ——`case (0, let y)`将匹配一个横坐标为`0`的点,并把这个点的纵坐标赋给临时的常量`y`。
|
这三个 case 都声明了常量`x`和`y`的占位符,用于临时获取元组`anotherPoint`的一个或两个值。第一个 case ——`case (let x, 0)`将匹配一个纵坐标为`0`的点,并把这个点的横坐标赋给临时的常量`x`。类似的,第二个 case ——`case (0, let y)`将匹配一个横坐标为`0`的点,并把这个点的纵坐标赋给临时的常量`y`。
|
||||||
|
|
||||||
一旦声明了这些临时的常量,它们就可以在其对应的 case 分支里引用。在这个例子中,它们用于简化`print(_:separator:terminator:)`的书写。
|
一旦声明了这些临时的常量,它们就可以在其对应的 case 分支里使用。在这个例子中,它们用于打印给定点的类型。
|
||||||
|
|
||||||
请注意,这个`switch`语句不包含默认分支。这是因为最后一个 case ——`case let(x, y)`声明了一个可以匹配余下所有值的元组。这使得`switch`语句已经完备了,因此不需要再书写默认分支。
|
请注意,这个`switch`语句不包含默认分支。这是因为最后一个 case ——`case let(x, y)`声明了一个可以匹配余下所有值的元组。这使得`switch`语句已经完备了,因此不需要再书写默认分支。
|
||||||
|
|
||||||
@ -486,14 +493,48 @@ case let (x, y):
|
|||||||
|
|
||||||
在上面的例子中,`switch`语句会判断某个点是否在绿色的对角线`x == y`上,是否在紫色的对角线`x == -y`上,或者不在对角线上。
|
在上面的例子中,`switch`语句会判断某个点是否在绿色的对角线`x == y`上,是否在紫色的对角线`x == -y`上,或者不在对角线上。
|
||||||
|
|
||||||
这三个 case 都声明了常量`x`和`y`的占位符,用于临时获取元组`yetAnotherPoint`的两个值。这些常量被用作`where`语句的一部分,从而创建一个动态的过滤器(filter)。当且仅当`where`语句的条件为`true`时,匹配到的 case 分支才会被执行。
|
这三个 case 都声明了常量`x`和`y`的占位符,用于临时获取元组`yetAnotherPoint`的两个值。这两个常量被用作`where`语句的一部分,从而创建一个动态的过滤器(filter)。当且仅当`where`语句的条件为`true`时,匹配到的 case 分支才会被执行。
|
||||||
|
|
||||||
就像是值绑定中的例子,由于最后一个 case 分支匹配了余下所有可能的值,`switch`语句就已经完备了,因此不需要再书写默认分支。
|
就像是值绑定中的例子,由于最后一个 case 分支匹配了余下所有可能的值,`switch`语句就已经完备了,因此不需要再书写默认分支。
|
||||||
|
|
||||||
|
<a name="compound_cases"></a>
|
||||||
|
#### 复合匹配(Compound Cases)
|
||||||
|
|
||||||
|
当多个条件可以使用同一种方法来处理时,可以将这几种可能放在同一个case后面,并且用逗号隔开。当case后面的任意一种模式匹配的时候,这条分支就会被匹配。并且,如果匹配列表过长,还可以分行书写:
|
||||||
|
|
||||||
|
```swift
|
||||||
|
let someCharacter: Character = "e"
|
||||||
|
switch someCharacter {
|
||||||
|
case "a", "e", "i", "o", "u":
|
||||||
|
print("\(someCharacter) is a vowel")
|
||||||
|
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
|
||||||
|
"n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
|
||||||
|
print("\(someCharacter) is a consonant")
|
||||||
|
default:
|
||||||
|
print("\(someCharacter) is not a vowel or a consonant")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
这个switch语句中的第一个case,匹配了英语中的五个小写原因字母。相似的,第二个case匹配了英语中所有的小写辅音字母。最终,default分支匹配了其它所有字符。
|
||||||
|
复合匹配同样可以包含值绑定。复合匹配里所有的匹配模式,都必须包含相同的值绑定。并且每一个绑定都必须获取到相同类型的值。这保证了,无论复合匹配中的哪个模式发生了匹配,分支体内的代码,都能获取到绑定的值,并且绑定的值都有一样的类型。
|
||||||
|
|
||||||
|
```swift
|
||||||
|
let stillAnotherPoint = (9, 0)
|
||||||
|
switch stillAnotherPoint {
|
||||||
|
case (let distance, 0), (0, let distance):
|
||||||
|
print("On an axis, \(distance) from the origin")
|
||||||
|
default:
|
||||||
|
print("Not on an axis")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
上面的case有两个模式:`(let distance, 0)`匹配了在x轴上的值,`(0, let distance)`匹配了在y轴上的值。两个模式都绑定了`distance`,并且`distance`在两种模式下,都是整型——这意味着分支体内的代码,只要case匹配,都可以获取到`distance`值
|
||||||
|
|
||||||
|
|
||||||
<a name="control_transfer_statements"></a>
|
<a name="control_transfer_statements"></a>
|
||||||
## 控制转移语句(Control Transfer Statements)
|
## 控制转移语句(Control Transfer Statements)
|
||||||
|
|
||||||
控制转移语句改变你代码的执行顺序,通过它你可以实现代码的跳转。Swift 有五种控制转移语句:
|
控制转移语句改变你代码的执行顺序,通过它可以实现代码的跳转。Swift 有五种控制转移语句:
|
||||||
|
|
||||||
- `continue`
|
- `continue`
|
||||||
- `break`
|
- `break`
|
||||||
@ -506,10 +547,7 @@ case let (x, y):
|
|||||||
<a name="continue"></a>
|
<a name="continue"></a>
|
||||||
### Continue
|
### Continue
|
||||||
|
|
||||||
`continue`语句告诉一个循环体立刻停止本次循环迭代,重新开始下次循环迭代。就好像在说“本次循环迭代我已经执行完了”,但是并不会离开整个循环体。
|
`continue`语句告诉一个循环体立刻停止本次循环,重新开始下次循环。就好像在说“本次循环我已经执行完了”,但是并不会离开整个循环体。
|
||||||
|
|
||||||
> 注意:
|
|
||||||
> 在一个带有条件和递增的 for 循环体中,调用`continue`语句后,迭代增量仍然会被计算求值。循环体继续像往常一样工作,仅仅只是循环体中的执行代码会被跳过。
|
|
||||||
|
|
||||||
下面的例子把一个小写字符串中的元音字母和空格字符移除,生成了一个含义模糊的短句:
|
下面的例子把一个小写字符串中的元音字母和空格字符移除,生成了一个含义模糊的短句:
|
||||||
|
|
||||||
@ -528,7 +566,7 @@ print(puzzleOutput)
|
|||||||
// 输出 "grtmndsthnklk"
|
// 输出 "grtmndsthnklk"
|
||||||
```
|
```
|
||||||
|
|
||||||
在上面的代码中,只要匹配到元音字母或者空格字符,就调用`continue`语句,使本次循环迭代结束,从新开始下次循环迭代。这种行为使`switch`匹配到元音字母和空格字符时不做处理,而不是让每一个匹配到的字符都被打印。
|
在上面的代码中,只要匹配到元音字母或者空格字符,就调用`continue`语句,使本次循环结束,重新开始下次循环。这种行为使`switch`匹配到元音字母和空格字符时不做处理,而不是让每一个匹配到的字符都被打印。
|
||||||
|
|
||||||
<a name="break"></a>
|
<a name="break"></a>
|
||||||
### Break
|
### Break
|
||||||
|
|||||||
Reference in New Issue
Block a user