From 8063e80cd415a0c6847c6aa9ed2e353e115705bc Mon Sep 17 00:00:00 2001
From: Linus <360725966@qq.com>
Date: Sun, 3 Apr 2016 14:14:15 +0800
Subject: [PATCH] update Control Flow
---
source/chapter2/05_Control_Flow.md | 140 +++++++++--------------------
1 file changed, 42 insertions(+), 98 deletions(-)
diff --git a/source/chapter2/05_Control_Flow.md b/source/chapter2/05_Control_Flow.md
index e6658d3d..012d6920 100755
--- a/source/chapter2/05_Control_Flow.md
+++ b/source/chapter2/05_Control_Flow.md
@@ -12,31 +12,27 @@
> 翻译:[Prayer](https://github.com/futantan)
> 校对:[shanks](http://codebuild.me)
+> 2.2
+> 翻译:[LinusLing](https://github.com/linusling)
+> 校对:[]()
+
本页包含内容:
-- [For 循环](#for_loops)
+- [For-In 循环](#for_in_loops)
- [While 循环](#while_loops)
- [条件语句](#conditional_statement)
- [控制转移语句(Control Transfer Statements)](#control_transfer_statements)
- [提前退出](#early_exit)
-- [检测API可用性](#checking_api_availability)
+- [检测 API 可用性](#checking_api_availability)
-Swift 提供了类似 C 语言的流程控制结构,包括可以多次执行任务的`for`和`while`循环,基于特定条件选择执行不同代码分支的`if`、`guard`和`switch`语句,还有控制流程跳转到其他代码的`break`和`continue`语句。
+Swift提供了多种流程控制结构,包括可以多次执行任务的`while`循环,基于特定条件选择执行不同代码分支的`if`、`guard`和`switch`语句,还有控制流程跳转到其他代码的`break`和`continue`语句。
-除了 C 语言里面传统的 for 循环,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`分句描述更复杂的匹配条件。
-
-## For 循环
-
-Swift 提供两种`for`循环形式来按照指定的次数执行一系列语句:
-
-* `for-in`循环对一个集合里面的每个元素执行一系列语句。
-* for 循环,用来重复执行一系列语句直到达成特定条件达成,一般通过在每次循环完成后增加计数器的值来实现。
-
-
-### For-In
+
+## For-In 循环
你可以使用`for-in`循环来遍历一个集合里面的所有元素,例如由数字表示的区间、数组中的元素、字符串中的字符。
@@ -99,53 +95,6 @@ for (animalName, legCount) in numberOfLegs {
字典元素的遍历顺序和插入顺序可能不同,字典的内容在内部是无序的,所以遍历元素时不能保证顺序。关于数组和字典,详情参见[集合类型](./04_Collection_Types.html)。
-
-### For
-
-除了`for-in`循环,Swift 提供使用条件判断和递增方法的标准 C 样式`for`循环:
-
-```swift
-for var index = 0; index < 3; ++index {
- print("index is \(index)")
-}
-// index is 0
-// index is 1
-// index is 2
-```
-
-下面是一般情况下这种循环方式的格式:
-
-```swift
-for initialization; condition; increment {
- statements
-}
-```
-
-和 C 语言中一样,分号将循环的定义分为 3 个部分,不同的是,Swift 不需要使用圆括号将“initialization; condition; increment”包括起来。
-
-这个循环执行流程如下:
-
-1. 循环首次启动时,*初始化表达式( initialization expression )*被调用一次,用来初始化循环所需的所有常量和变量。
-2. *条件表达式(condition expression)*被调用,如果表达式调用结果为`false`,循环结束,继续执行`for`循环关闭大括号(`}`)之后的代码。如果表达式调用结果为`true`,则会执行大括号内部的代码。
-3. 执行所有语句之后,执行*递增表达式(increment expression)*。通常会增加或减少计数器的值,或者根据语句输出来修改某一个初始化的变量。当递增表达式运行完成后,重复执行第 2 步,条件表达式会再次执行。
-
-
-在初始化表达式中声明的常量和变量(比如`var index = 0`)只在`for`循环的生命周期里有效。如果想在循环结束后访问`index`的值,你必须要在循环生命周期开始前声明`index`。
-
-```swift
-var index: Int
-for index = 0; index < 3; ++index {
- print("index is \(index)")
-}
-// index is 0
-// index is 1
-// index is 2
-print("The loop statements were executed \(index) times")
-// 输出 "The loop statements were executed 3 times
-```
-
-注意`index`在循环结束后最终的值是`3`而不是`2`。最后一次调用递增表达式`++index`会将`index`设置为`3`,从而导致`index < 3`条件为`false`,并终止循环。
-
## While 循环
@@ -169,7 +118,7 @@ while condition {
下面的例子来玩一个叫做蛇和梯子的小游戏,也叫做滑道和梯子:
-
+
游戏的规则如下:
@@ -212,11 +161,12 @@ while square < finalSquare {
print("Game over!")
```
-本例中使用了最简单的方法来模拟掷骰子。 `diceRoll`的值并不是一个随机数,而是以`0`为初始值,之后每一次`while`循环,`diceRoll`的值使用前置自增操作符(`++i`)来自增 1 ,然后检测是否超出了最大值。`++diceRoll`调用完成_后_,返回值等于`diceRoll`自增后的值。任何时候如果`diceRoll`的值等于7时,就超过了骰子的最大值,会被重置为`1`。所以`diceRoll`的取值顺序会一直是`1`,`2`,`3`,`4`,`5`,`6`,`1`,`2`。
+本例中使用了最简单的方法来模拟掷骰子。 `diceRoll`的值并不是一个随机数,而是以`0`为初始值,之后每一次`while`循环,`diceRoll`的值使用前置自增操作符(`++i`)来自增 1 ,然后检测是否超出了最大值。任何时候如果`diceRoll`的值等于 7 时,就超过了骰子的最大值,会被重置为`1`。所以`diceRoll`的取值顺序会一直是`1`。因此,`diceRoll` 所有的值只可能是 `1` ,`2`,`3`,`4`,`5`,`6`,`1`,`2` 等。
掷完骰子后,玩家向前移动`diceRoll`个方格,如果玩家移动超过了第 25 个方格,这个时候游戏结束,相应地,代码会在`square`增加`board[square]`的值向前或向后移动(遇到了梯子或者蛇)之前,检测`square`的值是否小于`board`的`count`属性。
-如果没有这个检测(`square < board.count`),`board[square]`可能会越界访问`board`数组,导致错误。例如如果`square`等于`26`, 代码会去尝试访问`board[26]`,超过数组的长度。
+> 注意:
+> 如果没有这个检测(`square < board.count`),`board[square]`可能会越界访问`board`数组,导致错误。例如如果`square`等于`26`, 代码会去尝试访问`board[26]`,超过数组的长度。
当本轮`while`循环运行完毕,会再检测循环条件是否需要再运行一次循环。如果玩家移动到或者超过第 25 个方格,循环条件结果为`false`,此时游戏结束。
@@ -325,7 +275,7 @@ if temperatureInFahrenheit <= 32 {
实际上,最后的`else`语句是可选的:
```swift
-temperatureInFahrenheit = 72
+temperatureInFahrenheit = 90
if temperatureInFahrenheit <= 32 {
print("It's very cold. Consider wearing a scarf.")
} else if temperatureInFahrenheit >= 86 {
@@ -346,7 +296,8 @@ if temperatureInFahrenheit <= 32 {
switch some value to consider {
case value 1:
respond to value 1
-case value 2, value 3:
+case value 2,
+ value 3:
respond to value 2 or 3
default:
otherwise, do something else
@@ -407,7 +358,8 @@ default:
```swift
switch some value to consider {
-case value 1, value 2:
+case value 1,
+ value 2:
statements
}
```
@@ -442,7 +394,7 @@ print("There are \(naturalCount) \(countedThings).")
// 输出 "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`语句遍历它。
@@ -471,7 +423,7 @@ default:
// 输出 "(1, 1) is inside the box"
```
-
+
在上面的例子中,`switch`语句会判断某个点是否是原点(0, 0),是否在红色的x轴上,是否在黄色y轴上,是否在一个以原点为中心的4x4的矩形里,或者在这个矩形外面。
@@ -498,7 +450,7 @@ case let (x, y):
// 输出 "on the x-axis with an x value of 2"
```
-
+
在上面的例子中,`switch`语句会判断某个点是否在红色的x轴上,是否在黄色y轴上,或者不在坐标轴上。
@@ -508,8 +460,6 @@ case let (x, y):
请注意,这个`switch`语句不包含默认分支。这是因为最后一个 case ——`case let(x, y)`声明了一个可以匹配余下所有值的元组。这使得`switch`语句已经完备了,因此不需要再书写默认分支。
-在上面的例子中,`x`和`y`是常量,这是因为没有必要在其对应的 case 分支中修改它们的值。然而,它们也可以是变量——程序将会创建临时变量,并用相应的值初始化它。修改这些变量只会影响其对应的 case 分支。
-
#### Where
@@ -530,7 +480,7 @@ case let (x, y):
// 输出 "(1, -1) is on the line x == -y"
```
-
+
在上面的例子中,`switch`语句会判断某个点是否在绿色的对角线`x == y`上,是否在紫色的对角线`x == -y`上,或者不在对角线上。
@@ -557,7 +507,7 @@ case let (x, y):
`continue`语句告诉一个循环体立刻停止本次循环迭代,重新开始下次循环迭代。就好像在说“本次循环迭代我已经执行完了”,但是并不会离开整个循环体。
> 注意:
-> 在一个带有条件和递增的for循环体中,调用`continue`语句后,迭代增量仍然会被计算求值。循环体继续像往常一样工作,仅仅只是循环体中的执行代码会被跳过。
+> 在一个带有条件和递增的 for 循环体中,调用`continue`语句后,迭代增量仍然会被计算求值。循环体继续像往常一样工作,仅仅只是循环体中的执行代码会被跳过。
下面的例子把一个小写字符串中的元音字母和空格字符移除,生成了一个含义模糊的短句:
@@ -573,7 +523,7 @@ for character in puzzleInput.characters {
}
}
print(puzzleOutput)
-// 输出 "grtmndsthnklk"
+ // 输出 "grtmndsthnklk"
```
在上面的代码中,只要匹配到元音字母或者空格字符,就调用`continue`语句,使本次循环迭代结束,从新开始下次循环迭代。这种行为使`switch`匹配到元音字母和空格字符时不做处理,而不是让每一个匹配到的字符都被打印。
@@ -668,11 +618,9 @@ print(description)
产生一个带标签的语句是通过在该语句的关键词的同一行前面放置一个标签,并且该标签后面还需带着一个冒号。下面是一个`while`循环体的语法,同样的规则适用于所有的循环体和`switch`代码块。
-```swift
-label name: while condition {
- statements
-}
-```
+> `label name`: while `condition` {
+> `statements`
+> }
下面的例子是在一个带有标签的`while`循环体中调用`break`和`continue`语句,该循环体是前面章节中*蛇和梯子*的改编版本。这次,游戏增加了一条额外的规则:
@@ -682,7 +630,7 @@ label name: while condition {
游戏的棋盘和之前一样:
-
+
`finalSquare`、`board`、`square`和`diceRoll`值被和之前一样的方式初始化:
@@ -724,8 +672,8 @@ print("Game over!")
- 如果骰子数将会使玩家的移动超出最后的方格,那么这种移动是不合法的,玩家需要重新掷骰子。`continue gameLoop`语句结束本次`while`循环的迭代,开始下一次循环迭代。
- 在剩余的所有情况中,骰子数产生的都是合法的移动。玩家向前移动骰子数个方格,然后游戏逻辑再处理玩家当前是否处于蛇头或者梯子的底部。本次循环迭代结束,控制跳转到`while`循环体的条件判断语句处,再决定是否能够继续执行下次循环迭代。
-> 注意:
-> 如果上述的`break`语句没有使用`gameLoop`标签,那么它将会中断`switch`代码块而不是`while`循环体。使用`gameLoop`标签清晰的表明了`break`想要中断的是哪个代码块。
+>注意:
+如果上述的`break`语句没有使用`gameLoop`标签,那么它将会中断`switch`代码块而不是`while`循环体。使用`gameLoop`标签清晰的表明了`break`想要中断的是哪个代码块。
同时请注意,当调用`continue gameLoop`去跳转到下一次循环迭代时,这里使用`gameLoop`标签并不是严格必须的。因为在这个游戏中,只有一个循环体,所以`continue`语句会影响到哪个循环体是没有歧义的。然而,`continue`语句使用`gameLoop`标签也是没有危害的。这样做符合标签的使用规则,同时参照旁边的`break gameLoop`,能够使游戏的逻辑更加清晰和易于理解。
@@ -738,38 +686,34 @@ func greet(person: [String: String]) {
guard let name = person["name"] else {
return
}
-
print("Hello \(name)")
guard let location = person["location"] else {
print("I hope the weather is nice near you.")
return
}
-
print("I hope the weather is nice in \(location).")
}
-
greet(["name": "John"])
-// prints "Hello John!"
-// prints "I hope the weather is nice near you."
+// 输出 "Hello John!"
+// 输出 "I hope the weather is nice near you."
greet(["name": "Jane", "location": "Cupertino"])
-// prints "Hello Jane!"
-// prints "I hope the weather is nice in Cupertino."
+// 输出 "Hello Jane!"
+// 输出 "I hope the weather is nice in Cupertino."
```
如果`guard`语句的条件被满足,则在保护语句的封闭大括号结束后继续执行代码。任何使用了可选绑定作为条件的一部分并被分配了值的变量或常量对于剩下的保护语句出现的代码段是可用的。
如果条件不被满足,在`else`分支上的代码就会被执行。这个分支必须转移控制以退出`guard`语句出现的代码段。它可以用控制转移语句如`return`,`break`,`continue`或者`throw`做这件事,或者调用一个不返回的方法或函数,例如`fatalError()`。
-相比于可以实现同样功能的`if`语句,按需使用`guard`语句会提升我们代码的可靠性。
-它可以使你的代码连贯的被执行而不需要将它包在`else`块中,它可以使你处理违反要求的代码使其接近要求。
+相比于可以实现同样功能的`if`语句,按需使用`guard`语句会提升我们代码的可靠性。它可以使你的代码连贯的被执行而不需要将它包在`else`块中,它可以使你处理违反要求的代码接近要求。
## 检测 API 可用性
Swift 有检查 API 可用性的内置支持,这可以确保我们不会不小心地使用对于当前部署目标不可用的 API。
-编译器使用 SDK 中的可用信息来验证我们的代码中使用的所有 API 在项目指定的部署目标上是否可用。如果我们尝试使用一个不可用的 API,Swift 会在编译期报错。
+编译器使用 SDK 中的可用信息来验证我们的代码中使用的所有 API 在项目指定的部署目标上是否可用。如果我们尝试使用一个不可用的 API,Swift 会在编译时报错。
我们使用一个可用性条件在一个`if`或`guard`语句中去有条件的执行一段代码,这取决于我们想要使用的 API 是否在运行时是可用的。编译器使用从可用性条件语句中获取的信息去验证在代码块中调用的 API 是否都可用。
@@ -781,14 +725,14 @@ if #available(iOS 9, OSX 10.10, *) {
}
```
-以上可用性条件指定了在 iOS 系统上,`if`段的代码仅会在 iOS 9 及更高版本的系统上执行;在 OS X,仅会在 OS X v10.10 及更高版本的系统上执行。最后一个参数,`*`,是必须写的,用于处理未来潜在的平台。
+以上可用性条件指定在 iOS,`if`段的代码仅仅在 iOS 9 及更高可运行;在 OS X,仅在 OS X v10.10 及更高可运行。最后一个参数,`*`,是必须的并且指定在任何其他平台上,`if`段的代码在最小可用部署目标指定项目中执行。
-在它的一般形式中,可用性条件获取了一系列平台名字和版本。平台名字可以是`iOS`,`OSX`或`watchOS`。除了特定的主板本号像 iOS 8,我们可以指定较小的版本号像 iOS 8.3 以及 OS X v10.10.3。
+在它普遍的形式中,可用性条件获取了平台名字和版本的清单。平台名字可以是`iOS`,`OSX`或`watchOS`。除了特定的主板本号像 iOS 8,我们可以指定较小的版本号像iOS 8.3 以及 OS X v10.10.3。
```swift
-if #available(platform name version, ..., *) {
- statements to execute if the APIs are available
+if #available(`platform name` `version`, `...`, *) {
+ `statements to execute if the APIs are available`
} else {
- fallback statements to execute if the APIs are unavailable
+ `fallback statements to execute if the APIs are unavailable`
}
```