diff --git a/source/chapter2/05_Control_Flow.md b/source/chapter2/05_Control_Flow.md index 668a6eb2..e56d1578 100755 --- a/source/chapter2/05_Control_Flow.md +++ b/source/chapter2/05_Control_Flow.md @@ -23,6 +23,9 @@ > 3.1 > 翻译:[qhd](https://github.com/qhd) 2017-04-17 +> 4.0 +> 翻译:[kemchenj](https://kemchenj.github.io/) 2017-09-21 + 本页包含内容: - [For-In 循环](#for_in_loops) @@ -34,14 +37,14 @@ 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 还可以匹配很多不同的模式,包括间隔匹配(interval match),元组(tuple)和转换到特定类型。`switch`语句的 case 中匹配的值可以绑定成临时常量或变量,在case体内使用,也可以用`where`来描述更复杂的匹配条件。 +Swift 的`switch`语句比 C 语言中更加强大。case 还可以匹配很多不同的模式,包括范围匹配,元组(tuple)和特定类型匹配。`switch`语句的 case 中匹配的值可以声明为临时常量或变量,在 case 作用域内使用,也可以配合`where`来描述更复杂的匹配条件。 ## For-In 循环 -你可以使用 `for-in` 循环来遍历一个集合中的所有元素,例如数组中的元素、数字范围或者字符串中的字符。 +你可以使用 `for-in` 循环来遍历一个集合中的所有元素,例如数组中的元素、范围内的数字或者字符串中的字符。 以下例子使用 `for-in` 遍历一个数组所有元素: @@ -56,7 +59,7 @@ for name in names { // Hello, Jack! ``` -你也可以通过遍历一个字典来访问它的键值对。遍历字典时,字典的每项元素会以 `(key, value)` 元组的形式返回,你可以在 `for-in` 循环中使用显式的常量名称来解读 `(key, value)` 元组。下面的例子中,字典的键解读为常量 `animalName`,字典的值会被解读为常量 `legCount`: +你也可以通过遍历一个字典来访问它的键值对。遍历字典时,字典的每项元素会以 `(key, value)` 元组的形式返回,你可以在 `for-in` 循环中使用显式的常量名称来解读 `(key, value)` 元组。下面的例子中,字典的键声明会为 `animalName` 常量,字典的值会声明为 `legCount` 常量: ```swift let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4] @@ -68,9 +71,9 @@ for (animalName, legCount) in numberOfLegs { // cats have 4 legs ``` -字典的内容本质上是无序的,遍历元素时不能保证顺序。特别地,将元素插入一个字典的顺序并不会决定它们被遍历的顺序。关于数组和字典,详情参见[集合类型](./04_Collection_Types.html)。 +字典的内容理论上是无序的,遍历元素时的顺序是无法确定的。将元素插入字典的顺序并不会决定它们被遍历的顺序。关于数组和字典的细节,参见[集合类型](./04_Collection_Types.html)。 -`for-in` 循环还可以使用数字范围。下面的例子用来输出乘 5 乘法表前面一部分内容: +`for-in` 循环还可以使用数字范围。下面的例子用来输出乘法表的一部分内容: ```swift for index in 1...5 { @@ -102,12 +105,12 @@ print("\(base) to the power of \(power) is \(answer)") 这个例子计算 base 这个数的 power 次幂(本例中,是 `3` 的 `10` 次幂),从 `1`( `3` 的 `0` 次幂)开始做 `3` 的乘法, 进行 `10` 次,使用 `1` 到 `10` 的闭区间循环。这个计算并不需要知道每一次循环中计数器具体的值,只需要执行了正确的循环次数即可。下划线符号 `_` (替代循环中的变量)能够忽略当前值,并且不提供循环遍历时对值的访问。 -在某些情况下,你可能不想使用闭区间,包括两个端点。在一个手表上每分钟绘制一个刻度线。要绘制 `60` 个刻度,从 `0` 分钟开始。使用半开区间运算符(`..<`)来包含下限,但不包括上限。有关区间的更多信息,请参阅[区间运算符](./02_Basic_Operators.html#range_operators)。 +在某些情况下,你可能不想使用闭区间,包括两个端点。想象一下,你在一个手表上绘制分钟的刻度线。总共 `60` 个刻度,从 `0` 分开始。使用半开区间运算符(`..<`)来表示一个左闭右开的区间。有关区间的更多信息,请参阅[区间运算符](./02_Basic_Operators.html#range_operators)。 ``` let minutes = 60 for tickMark in 0.. 注意: -> 如果没有这个检测(`square < board.count`),`board[square]`可能会越界访问`board`数组,导致错误。如果`square`等于`26`, 代码会去尝试访问`board[26]`,超过数组的长度。 +> 如果没有这个检测(`square < board.count`),`board[square]`可能会越界访问`board`数组,导致错误。 当本轮`while`循环运行完毕,会再检测循环条件是否需要再运行一次循环。如果玩家移动到或者超过第 25 个方格,循环条件结果为`false`,此时游戏结束。 @@ -255,7 +258,7 @@ print("Game over!") 检测完玩家是否踩在梯子或者蛇上之后,开始掷骰子,然后玩家向前移动`diceRoll`个方格,本轮循环结束。 -循环条件(`while square < finalSquare`)和`while`方式相同,但是只会在循环结束后进行计算。在这个游戏中,`repeat-while`表现得比`while`循环更好。`repeat-while`方式会在条件判断`square`没有超出后直接运行`square += board[square]`,这种方式可以去掉`while`版本中的数组越界判断。 +循环条件(`while square < finalSquare`)和`while`方式相同,但是只会在循环结束后进行计算。在这个游戏中,`repeat-while`表现得比`while`循环更好。`repeat-while`方式会在条件判断`square`没有超出后直接运行`square += board[square]`,这种方式可以比起前面 `while` 循环的版本,可以省去数组越界的检查。 ## 条件语句 @@ -416,7 +419,7 @@ case 分支的模式也可以是一个值的区间。下面的例子展示了如 ```swift let approximateCount = 62 let countedThings = "moons orbiting Saturn" -var naturalCount: String +let naturalCount: String switch approximateCount { case 0: naturalCount = "no" @@ -450,15 +453,15 @@ print("There are \(naturalCount) \(countedThings).") let somePoint = (1, 1) switch somePoint { case (0, 0): - print("(0, 0) is at the origin") + print("\(somePoint) is at the origin") case (_, 0): - print("(\(somePoint.0), 0) is on the x-axis") + print("\(somePoint) is on the x-axis") case (0, _): - print("(0, \(somePoint.1)) is on the y-axis") + print("\(somePoint) is on the y-axis") case (-2...2, -2...2): - print("(\(somePoint.0), \(somePoint.1)) is inside the box") + print("\(somePoint) is inside the box") default: - print("(\(somePoint.0), \(somePoint.1)) is outside of the box") + print("\(somePoint) is outside of the box") } // 输出 "(1, 1) is inside the box" ``` @@ -473,9 +476,9 @@ default: #### 值绑定(Value Bindings) -case 分支允许将匹配的值绑定到一个临时的常量或变量,并且在case分支体内使用 —— 这种行为被称为*值绑定*(value binding),因为匹配的值在case分支体内,与临时的常量或变量绑定。 +case 分支允许将匹配的值声明为临时常量或变量,并且在case分支体内使用 —— 这种行为被称为*值绑定*(value binding),因为匹配的值在case分支体内,与临时的常量或变量绑定。 -下面的例子展示了如何在一个`(Int, Int)`类型的元组中使用值绑定来分类下图中的点(x, y): +下面的例子将下图中的点(x, y),使用`(Int, Int)`类型的元组表示,然后分类表示: ```swift let anotherPoint = (2, 0) @@ -589,7 +592,7 @@ default: ```swift let puzzleInput = "great minds think alike" var puzzleOutput = "" -for character in puzzleInput.characters { +for character in puzzleInput { switch character { case "a", "e", "i", "o", "u", " ": continue @@ -606,7 +609,7 @@ print(puzzleOutput) ### Break -`break`语句会立刻结束整个控制流的执行。当你想要更早的结束一个`switch`代码块或者一个循环体时,你都可以使用`break`语句。 +`break`语句会立刻结束整个控制流的执行。`break` 可以在 `switch` 或循环语句中使用,用来提前结束`switch`或循环语句。 #### 循环语句中的 break @@ -657,7 +660,7 @@ if let integerValue = possibleIntegerValue { ### 贯穿 -Swift 中的`switch`不会从上一个 case 分支落入到下一个 case 分支中。相反,只要第一个匹配到的 case 分支完成了它需要执行的语句,整个`switch`代码块完成了它的执行。相比之下,C 语言要求你显式地插入`break`语句到每个 case 分支的末尾来阻止自动落入到下一个 case 分支中。Swift 的这种避免默认落入到下一个分支中的特性意味着它的`switch` 功能要比 C 语言的更加清晰和可预测,可以避免无意识地执行多个 case 分支从而引发的错误。 +在 Swift 里,`switch`语句不会从上一个 case 分支跳转到下一个 case 分支中。相反,只要第一个匹配到的 case 分支完成了它需要执行的语句,整个`switch`代码块完成了它的执行。相比之下,C 语言要求你显式地插入`break`语句到每个 case 分支的末尾来阻止自动落入到下一个 case 分支中。Swift 的这种避免默认落入到下一个分支中的特性意味着它的`switch` 功能要比 C 语言的更加清晰和可预测,可以避免无意识地执行多个 case 分支从而引发的错误。 如果你确实需要 C 风格的贯穿的特性,你可以在每个需要该特性的 case 分支中使用`fallthrough`关键字。下面的例子使用`fallthrough`来创建一个数字的描述语句。 @@ -801,9 +804,9 @@ if #available(iOS 10, macOS 10.12, *) { } ``` -以上可用性条件指定,在iOS中,`if`语句的代码块仅仅在 iOS 10 及更高的系统下运行;在 macOS中,仅在 macOS 10.12 及更高才会运行。最后一个参数,`*`,是必须的,用于指定在所有其它平台中,如果版本号高于你的设备指定的最低版本,if语句的代码块将会运行。 +以上可用性条件指定,`if`语句的代码块仅仅在 iOS 10 或 macOS 10.12 及更高版本才运行。最后一个参数,`*`,是必须的,用于指定在所有其它平台中,如果版本号高于你的设备指定的最低版本,if语句的代码块将会运行。 -在它一般的形式中,可用性条件使用了一个平台名字和版本的列表。平台名字可以是`iOS`,`macOS`,`watchOS`和`tvOS`——请访问[声明属性](../chapter3/06_Attributes.html)来获取完整列表。除了指定像 iOS 8的主板本号,我们可以指定像iOS 8.3 以及 macOS 10.10.3的子版本号。 +在它一般的形式中,可用性条件使用了一个平台名字和版本的列表。平台名字可以是`iOS`,`macOS`,`watchOS`和`tvOS`——请访问[声明属性](../chapter3/06_Attributes.html)来获取完整列表。除了指定像 iOS 8 或 macOS 10.10 的大版本号,也可以指定像 iOS 8.3 以及 macOS 10.10.3 的小版本号。 ```swift if #available(platform name version, ..., *) {