From e24c2eb213f40552710b0243e7d5cf8c79521f09 Mon Sep 17 00:00:00 2001
From: chenmingjia <564575471@qq.com>
Date: Fri, 16 Sep 2016 10:42:14 +0800
Subject: [PATCH 01/32] [Translate] Translate Statement in Swift 3.0.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Swift 3.0 Statement 已经补充完毕,主要是行控制语句部分更新和移除Boolean协议的讨论
---
source/chapter3/10_Statements.md | 43 +++++++++++++++-----------------
1 file changed, 20 insertions(+), 23 deletions(-)
diff --git a/source/chapter3/10_Statements.md b/source/chapter3/10_Statements.md
index 0b7fd6a8..8edd883c 100755
--- a/source/chapter3/10_Statements.md
+++ b/source/chapter3/10_Statements.md
@@ -12,6 +12,9 @@
> 2.2
> 翻译:[chenmingbiao](https://github.com/chenmingbiao)
+> 3.0
+> 翻译:[chenmingjia](https://github.com/chenmingjia)
+
本页包含内容:
- [循环语句](#loop_statements)
@@ -108,7 +111,7 @@ while 条件 {
由于会在执行循环体中的语句前判断条件的值,因此循环体中的语句可能会被执行若干次,也可能一次也不会被执行。
-条件的结果必须符合 `BooleanType` 协议。另外,条件语句也可以使用可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.md#optional_binding)。
+条件的结果必须是Bool类型或者Bool的桥接类型。另外,条件语句也可以使用可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.md#optional_binding)。
> while 语句语法
@@ -124,18 +127,13 @@ while 条件 {
> *条件列表* → [*条件*](#condition) | [*条件*](#condition) **,** [*条件列表*](#condition-list)
-> *条件* → [*可用性条件*](#availability-condition) | [*case条件*](#case-condition) | [*可选绑定条件*](#optional-binding-condition)
+> *条件* → [*表达式*](04_Expressions.md#expression) |[*可用性条件*](#availability-condition) | [*case条件*](#case-condition) | [*可选绑定条件*](#optional-binding-condition)
-> *case 条件* → **case** [*模式*](07_Patterns.md#pattern) [*构造器*](05_Declarations.md#initializer) [where子句](#where-clause)可选
+> *case 条件* → **case** [*模式*](07_Patterns.md#pattern) [*构造器*](05_Declarations.md#initializer)
-> *可选绑定条件* → [*可选绑定头*](#optional-binding-head) [*可选绑定附加列表*](#optional-binding-continuation-list)可选 [*where子句*](#where-clause)可选
-
-> *可选绑定头* → **let** [*模式*](07_Patterns.md#pattern) [*构造器*](05_Declarations.md#initializer) | **var** [*模式*](07_Patterns.md#pattern) [*构造器*](05_Declarations.md#initializer)
-
-> *可选绑定附加部分列表* → [*可选绑定附加部分*](#optional-binding-continuation) | [*可选绑定附加部分*](#optional-binding-continuation) **,** [*可选绑定附加部分列表*](#optional-binding-continuation-list)
-
-> *可选绑定附加部分* → [*模式*](07_Patterns.md#pattern) [*构造器*](05_Declarations.md#initializer) | [*可选绑定头*](#optional-binding-head)
+> *可选绑定条件* → **let** [*模式*](07_Patterns.md#pattern) [*构造器*](05_Declarations.md#initializer) | **var** [*模式*](07_Patterns.md#pattern) [*构造器*](05_Declarations.md#initializer)
+
### Repeat-While 语句
@@ -157,7 +155,7 @@ repeat {
由于条件的值是在循环体中的语句执行后才进行判断,因此循环体中的语句至少会被执行一次。
-条件的结果必须符合 `BooleanType` 协议。另外,条件语句也可以使用可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.md#optional_binding)。
+条件的结果必须是Bool类型或者Bool的桥接类型。另外,条件语句也可以使用可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.md#optional_binding)。
> repeat-while 语句语法
@@ -213,7 +211,7 @@ if 条件1 {
}
```
-`if` 语句中条件的结果必须符合 `BooleanType` 协议。另外,条件语句也可以使用可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.md#optional_binding)。
+`if` 语句中条件的结果必须是Bool类型或者Bool的桥接类型。另外,条件语句也可以使用可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.md#optional_binding)。
> if 语句语法
@@ -234,7 +232,7 @@ guard 条件 else {
}
```
-`guard` 语句中条件的结果必须符合 `BooleanType` 协议。另外,条件也可以是一条可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.html#optional_binding)。
+`guard` 语句中条件的结果必须是Bool类型或者Bool的桥接类型。另外,条件也可以是一条可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.html#optional_binding)。
在 `guard` 语句中进行可选绑定的常量或者变量,其可用范围从声明开始直到作用域结束。
@@ -281,7 +279,7 @@ default:
case let (x, y) where x == y:
```
-正如上面这个例子,也可以在模式中使用 `let`(或 `var`)语句来绑定常量(或变量)。这些常量(或变量)可以在对应的 `where` 子句以及 `case` 中的代码中使用。但是,如果一个 `case` 中含有多个模式,那么这些模式都不能绑定常量(或变量)。
+正如上面这个例子,也可以在模式中使用 `let`(或 `var`)语句来绑定常量(或变量)。这些常量(或变量)可以在对应的 `where` 子句以及 `case` 中的代码中使用。但是,如果一个 `case` 中含有多个模式,所有的模式必须包含相同的常量(或变量)绑定,并且每一个绑定的常量(或变量)必须在所有的条件模式中都有相同的类型。
`switch` 语句也可以包含默认分支,使用 `default` 关键字表示。只有所有 `case` 都无法匹配控制表达式时,默认分支中的代码才会被执行。一个 `switch` 语句只能有一个默认分支,而且必须在 `switch` 语句的最后面。
@@ -606,19 +604,18 @@ do {
行控制语句形式如下:
-> \#line `行号` `文件名`
+> \#sourceLocation(file: `文件名` , line:`行号`)
+> \#sourceLocation()
-行控制语句会改变该语句之后的代码中的字面量表达式 `#line` 和 `#file` 所表示的值。`行号` 是一个大于 0 的整形字面量,会改变 `#line` 表达式的值。`文件名` 是一个字符串字面量,会改变 `#file` 表达式的值。
+第一种的行控制语句会改变该语句之后的代码中的字面量表达式 `#line` 和 `#file` 所表示的值。`行号` 是一个大于 0 的整形字面量,会改变 `#line` 表达式的值。`文件名` 是一个字符串字面量,会改变 `#file` 表达式的值。
-你可以只写 `#line`,而不指定行号和文件名,从而将源代码的定位信息重置回默认的行号和文件名。
-
-`#line` 标记具有两种含义,作为行控制语句使用时必须独占一行,而且不能是源代码文件的最后一行。否则,它将作为字面量表达式使用,详情请参阅 [字面量表达式](04_Expressions.md#literal_expression)。
+第二种的行控制语句, `#sourceLocation()`,会将源代码的定位信息重置回默认的行号和文件名。
> 行控制语句语法
-> *行控制语句* → **#line**
-> *行控制语句* → **#line** [*行号*](#line-number) [*文件名*](#file-name)
+> *行控制语句* → **#sourceLocation(file:[*文件名*](#file-name),line:[*行号*](#line-number))**
+> *行控制语句* → **#sourceLocation()**
> *行号* → 大于 0 的十进制整数
@@ -663,5 +660,5 @@ if #available(平台名称 版本, ..., *) {
> *平台版本* → [十进制数字](02_Lexical_Structure.md#decimal-digits)
> *平台版本* → [十进制数字](02_Lexical_Structure.md#decimal-digits) **.** [十进制数字](02_Lexical_Structure.md#decimal-digits)
> *平台版本* → [十进制数字](02_Lexical_Structure.md#decimal-digits) **.** [十进制数字](02_Lexical_Structure.md#decimal-digits) **.** [十进制数字](02_Lexical_Structure.md#decimal-digits)
-
-
+
+
From 64530ef5d0681ae6ed5ffbca169d9a2782153b4b Mon Sep 17 00:00:00 2001
From: chenmingjia <564575471@qq.com>
Date: Fri, 16 Sep 2016 10:43:41 +0800
Subject: [PATCH 02/32] [Translate] Translate Statement in Swift 3.0.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Swift 3.0 Statement 已经补充完毕,主要是行控制语句部分更新和移除Boolean协议的讨论
---
source/chapter3/10_Statements.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/source/chapter3/10_Statements.md b/source/chapter3/10_Statements.md
index 8edd883c..83e7b8c1 100755
--- a/source/chapter3/10_Statements.md
+++ b/source/chapter3/10_Statements.md
@@ -605,6 +605,7 @@ do {
行控制语句形式如下:
> \#sourceLocation(file: `文件名` , line:`行号`)
+
> \#sourceLocation()
第一种的行控制语句会改变该语句之后的代码中的字面量表达式 `#line` 和 `#file` 所表示的值。`行号` 是一个大于 0 的整形字面量,会改变 `#line` 表达式的值。`文件名` 是一个字符串字面量,会改变 `#file` 表达式的值。
From 9573e34aa2d6dae22b6ffd1c077972b38a9339f6 Mon Sep 17 00:00:00 2001
From: chenmingjia <564575471@qq.com>
Date: Fri, 16 Sep 2016 10:45:19 +0800
Subject: [PATCH 03/32] [Translate] Translate Statement in Swift 3.0.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Swift 3.0 Statement 已经补充完毕,主要是行控制语句部分更新和移除Boolean协议的讨论
---
source/chapter3/10_Statements.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/source/chapter3/10_Statements.md b/source/chapter3/10_Statements.md
index 83e7b8c1..c5bcabe3 100755
--- a/source/chapter3/10_Statements.md
+++ b/source/chapter3/10_Statements.md
@@ -616,7 +616,7 @@ do {
> 行控制语句语法
> *行控制语句* → **#sourceLocation(file:[*文件名*](#file-name),line:[*行号*](#line-number))**
-> *行控制语句* → **#sourceLocation()**
+> *行控制语句* → **#sourceLocation()**
> *行号* → 大于 0 的十进制整数
From 6a9b24881e9c5c067d75660adbe71685cb6dcc2d Mon Sep 17 00:00:00 2001
From: chenmingbiao
Date: Sat, 17 Sep 2016 16:21:59 +0800
Subject: [PATCH 04/32] update chapter 'The Basics' to swift 3
---
source/chapter2/01_The_Basics.md | 229 ++++++++++---------
source/chapter2/03_Strings_and_Characters.md | 2 +
2 files changed, 126 insertions(+), 105 deletions(-)
diff --git a/source/chapter2/01_The_Basics.md b/source/chapter2/01_The_Basics.md
index bd48d27f..84e4c1db 100755
--- a/source/chapter2/01_The_Basics.md
+++ b/source/chapter2/01_The_Basics.md
@@ -13,7 +13,12 @@
> 校对:[shanks](http://codebuild.me),[overtrue](https://github.com/overtrue)
>
> 2.2
-> 校对:[SketchK](https://github.com/SketchK) 2016-05-11
+> 校对:[SketchK](https://github.com/SketchK)
+>
+> 3.0
+> 校对:[CMB](https://github.com/chenmingbiao)
+>
+> 版本日期:2016-09-13
本页包含内容:
@@ -45,27 +50,27 @@
- [错误处理](#error_handling)
- [断言](#assertions)
-Swift 是一门开发 iOS, OS X 和 watchOS 应用的新语言。然而,如果你有 C 或者 Objective-C 开发经验的话,你会发现 Swift 的很多内容都是你熟悉的。
+Swift 是一门开发 iOS, macOS, watchOS 和 tvOS 应用的新语言。然而,如果你有 C 或者 Objective-C 开发经验的话,你会发现 Swift 的很多内容都是你熟悉的。
-Swift 包含了 C 和 Objective-C 上所有基础数据类型,`Int`表示整型值;`Double`和`Float`表示浮点型值;`Bool`是布尔型值;`String`是文本型数据。Swift 还提供了三个基本的集合类型,`Array`,`Set`和`Dictionary`,详见[集合类型](04_Collection_Types.html)。
+Swift 包含了 C 和 Objective-C 上所有基础数据类型,`Int`表示整型值; `Double` 和 `Float` 表示浮点型值; `Bool` 是布尔型值;`String` 是文本型数据。 Swift 还提供了三个基本的集合类型,`Array` ,`Set` 和 `Dictionary` ,详见[集合类型](04_Collection_Types.html)。
就像 C 语言一样,Swift 使用变量来进行存储并通过变量名来关联值。在 Swift 中,广泛的使用着值不可变的变量,它们就是常量,而且比 C 语言的常量更强大。在 Swift 中,如果你要处理的值不需要改变,那使用常量可以让你的代码更加安全并且更清晰地表达你的意图。
除了我们熟悉的类型,Swift 还增加了 Objective-C 中没有的高阶数据类型比如元组(Tuple)。元组可以让你创建或者传递一组数据,比如作为函数的返回值时,你可以用一个元组可以返回多个值。
-Swift 还增加了可选(Optional)类型,用于处理值缺失的情况。可选表示“那儿有一个值,并且它等于 x ”或者“那儿没有值”。可选有点像在 Objective-C 中使用`nil`,但是它可以用在任何类型上,不仅仅是类。可选类型比 Objective-C 中的`nil`指针更加安全也更具表现力,它是 Swift 许多强大特性的重要组成部分。
+Swift 还增加了可选(Optional)类型,用于处理值缺失的情况。可选表示 “那儿有一个值,并且它等于 x ” 或者 “那儿没有值” 。可选有点像在 Objective-C 中使用 `nil` ,但是它可以用在任何类型上,不仅仅是类。可选类型比 Objective-C 中的 `nil` 指针更加安全也更具表现力,它是 Swift 许多强大特性的重要组成部分。
-Swift 是一门类型安全的语言,可选类型就是一个很好的例子。Swift 可以让你清楚地知道值的类型。如果你的代码期望得到一个`String`,类型安全会阻止你不小心传入一个`Int`。你可以在开发阶段尽早发现并修正错误。
+Swift 是一门类型安全的语言,可选类型就是一个很好的例子。Swift 可以让你清楚地知道值的类型。如果你的代码期望得到一个 `String` ,类型安全会阻止你不小心传入一个 `Int` 。同样的,如果你的代码期望得到一个 `String`,类型安全会阻止你意外传入一个可选的 `String` 。你可以在开发阶段尽早发现并修正错误。
## 常量和变量
-常量和变量把一个名字(比如`maximumNumberOfLoginAttempts`或者`welcomeMessage`)和一个指定类型的值(比如数字`10`或者字符串`"Hello"`)关联起来。常量的值一旦设定就不能改变,而变量的值可以随意更改。
+常量和变量把一个名字(比如 `maximumNumberOfLoginAttempts` 或者 `welcomeMessage` )和一个指定类型的值(比如数字 `10` 或者字符串 `"Hello"` )关联起来。常量的值一旦设定就不能改变,而变量的值可以随意更改。
### 声明常量和变量
-常量和变量必须在使用前声明,用`let`来声明常量,用`var`来声明变量。下面的例子展示了如何用常量和变量来记录用户尝试登录的次数:
+常量和变量必须在使用前声明,用 `let` 来声明常量,用 `var` 来声明变量。下面的例子展示了如何用常量和变量来记录用户尝试登录的次数:
```swift
let maximumNumberOfLoginAttempts = 10
@@ -74,7 +79,7 @@ var currentLoginAttempt = 0
这两行代码可以被理解为:
-“声明一个名字是`maximumNumberOfLoginAttempts`的新常量,并给它一个值`10`。然后,声明一个名字是`currentLoginAttempt`的变量并将它的值初始化为`0`。”
+“声明一个名字是 `maximumNumberOfLoginAttempts` 的新常量,并给它一个值 `10` 。然后,声明一个名字是 `currentLoginAttempt` 的变量并将它的值初始化为 `0` 。”
在这个例子中,允许的最大尝试登录次数被声明为一个常量,因为这个值不会改变。当前尝试登录次数被声明为一个变量,因为每次尝试登录失败的时候都需要增加这个值。
@@ -84,15 +89,15 @@ var currentLoginAttempt = 0
var x = 0.0, y = 0.0, z = 0.0
```
->注意:
-如果你的代码中有不需要改变的值,请使用`let`关键字将它声明为常量。只将需要改变的值声明为变量。
+> 注意:
+> 如果你的代码中有不需要改变的值,请使用 `let` 关键字将它声明为常量。只将需要改变的值声明为变量。
### 类型标注
当你声明常量或者变量的时候可以加上类型标注(type annotation),说明常量或者变量中要存储的值的类型。如果要添加类型标注,需要在常量或者变量名后面加上一个冒号和空格,然后加上类型名称。
-这个例子给`welcomeMessage`变量添加了类型标注,表示这个变量可以存储`String`类型的值:
+这个例子给 `welcomeMessage` 变量添加了类型标注,表示这个变量可以存储 `String` 类型的值:
```swift
var welcomeMessage: String
@@ -100,11 +105,11 @@ var welcomeMessage: String
声明中的冒号代表着“是...类型”,所以这行代码可以被理解为:
-“声明一个类型为`String`,名字为`welcomeMessage`的变量。”
+“声明一个类型为 `String` ,名字为 `welcomeMessage` 的变量。”
-“类型为`String`”的意思是“可以存储任意`String`类型的值。”
+“类型为 `String` ”的意思是“可以存储任意 `String` 类型的值。”
-`welcomeMessage`变量现在可以被设置成任意字符串:
+`welcomeMessage` 变量现在可以被设置成任意字符串:
```swift
welcomeMessage = "Hello"
@@ -117,7 +122,7 @@ var red, green, blue: Double
```
> 注意:
-一般来说你很少需要写类型标注。如果你在声明常量或者变量的时候赋了一个初始值,Swift可以推断出这个常量或者变量的类型,请参考[类型安全和类型推断](#type_safety_and_type_inference)。在上面的例子中,没有给`welcomeMessage`赋初始值,所以变量`welcomeMessage`的类型是通过一个类型标注指定的,而不是通过初始值推断的。
+> 一般来说你很少需要写类型标注。如果你在声明常量或者变量的时候赋了一个初始值,Swift可以推断出这个常量或者变量的类型,请参考[类型安全和类型推断](#type_safety_and_type_inference)。在上面的例子中,没有给 `welcomeMessage` 赋初始值,所以变量 `welcomeMessage` 的类型是通过一个类型标注指定的,而不是通过初始值推断的。
### 常量和变量的命名
@@ -135,7 +140,7 @@ let 🐶🐮 = "dogcow"
一旦你将常量或者变量声明为确定的类型,你就不能使用相同的名字再次进行声明,或者改变其存储的值的类型。同时,你也不能将常量与变量进行互转。
> 注意:
-如果你需要使用与Swift保留关键字相同的名称作为常量或者变量名,你可以使用反引号(`)将关键字包围的方式将其作为名字使用。无论如何,你应当避免使用关键字作为常量或变量名,除非你别无选择。
+> 如果你需要使用与Swift保留关键字相同的名称作为常量或者变量名,你可以使用反引号(`)将关键字包围的方式将其作为名字使用。无论如何,你应当避免使用关键字作为常量或变量名,除非你别无选择。
你可以更改现有的变量值为其他同类型的值,在下面的例子中,`friendlyWelcome`的值从`"Hello!"`改为了`"Bonjour!"`:
@@ -163,7 +168,7 @@ print(friendlyWelcome)
// 输出 "Bonjour!"
```
-`print(_:separator:terminator:)`是一个用来输出一个或多个值到适当输出区的全局函数。如果你用 Xcode,`print(_:separator:terminator:)`将会输出内容到“console”面板上。`separator`和`terminator`参数具有默认值,因此你调用这个函数的时候可以忽略它们。默认情况下,该函数通过添加换行符来结束当前行。如果不想换行,可以传递一个空字符串给`terminator`参数--例如,`print(someValue, terminator:"")`。关于参数默认值的更多信息,请参考[默认参数值](./06_Functions.html#default_parameter_values)。
+`print(_:separator:terminator:)` 是一个用来输出一个或多个值到适当输出区的全局函数。如果你用 Xcode,`print(_:separator:terminator:)` 将会输出内容到“console”面板上。`separator` 和 `terminator` 参数具有默认值,因此你调用这个函数的时候可以忽略它们。默认情况下,该函数通过添加换行符来结束当前行。如果不想换行,可以传递一个空字符串给 `terminator` 参数--例如,`print(someValue, terminator:"")` 。关于参数默认值的更多信息,请参考[默认参数值](./06_Functions.html#default_parameter_values)。
Swift 用字符串插值(string interpolation)的方式把常量名或者变量名当做占位符加入到长字符串中,Swift 会用当前常量或变量的值替换这些占位符。将常量或变量名放入圆括号中,并在开括号前使用反斜杠将其转义:
@@ -214,38 +219,39 @@ let cat = "🐱"; print(cat)
## 整数
-整数就是没有小数部分的数字,比如`42`和`-23`。整数可以是`有符号`(正、负、零)或者`无符号`(正、零)。
+整数就是没有小数部分的数字,比如 `42` 和 `-23` 。整数可以是 `有符号`(正、负、零)或者 `无符号`(正、零)。
-Swift 提供了8,16,32和64位的有符号和无符号整数类型。这些整数类型和 C 语言的命名方式很像,比如8位无符号整数类型是`UInt8`,32位有符号整数类型是`Int32`。就像 Swift 的其他类型一样,整数类型采用大写命名法。
+Swift 提供了8,16,32和64位的有符号和无符号整数类型。这些整数类型和 C 语言的命名方式很像,比如8位无符号整数类型是`UInt8`,32位有符号整数类型是 `Int32` 。就像 Swift 的其他类型一样,整数类型采用大写命名法。
### 整数范围
-你可以访问不同整数类型的`min`和`max`属性来获取对应类型的最小值和最大值:
+你可以访问不同整数类型的 `min` 和 `max` 属性来获取对应类型的最小值和最大值:
```swift
let minValue = UInt8.min // minValue 为 0,是 UInt8 类型
let maxValue = UInt8.max // maxValue 为 255,是 UInt8 类型
-```
-`min`和`max`所传回值的类型,正是其所对的整数类型(如上例UInt8, 所传回的类型是UInt8),可用在表达式中相同类型值旁。
+```
+
+`min` 和 `max` 所传回值的类型,正是其所对的整数类型(如上例UInt8, 所传回的类型是UInt8),可用在表达式中相同类型值旁。
### Int
一般来说,你不需要专门指定整数的长度。Swift 提供了一个特殊的整数类型`Int`,长度与当前平台的原生字长相同:
-* 在32位平台上,`Int`和`Int32`长度相同。
-* 在64位平台上,`Int`和`Int64`长度相同。
+* 在32位平台上,`Int` 和 `Int32` 长度相同。
+* 在64位平台上,`Int` 和 `Int64` 长度相同。
-除非你需要特定长度的整数,一般来说使用`Int`就够了。这可以提高代码一致性和可复用性。即使是在32位平台上,`Int`可以存储的整数范围也可以达到`-2,147,483,648`~`2,147,483,647`,大多数时候这已经足够大了。
+除非你需要特定长度的整数,一般来说使用 `Int` 就够了。这可以提高代码一致性和可复用性。即使是在32位平台上,`Int` 可以存储的整数范围也可以达到 `-2,147,483,648` ~ `2,147,483,647` ,大多数时候这已经足够大了。
### UInt
-Swift 也提供了一个特殊的无符号类型`UInt`,长度与当前平台的原生字长相同:
+Swift 也提供了一个特殊的无符号类型 `UInt`,长度与当前平台的原生字长相同:
-* 在32位平台上,`UInt`和`UInt32`长度相同。
-* 在64位平台上,`UInt`和`UInt64`长度相同。
+* 在32位平台上,`UInt` 和 `UInt32` 长度相同。
+* 在64位平台上,`UInt` 和 `UInt64` 长度相同。
> 注意:
尽量不要使用`UInt`,除非你真的需要存储一个和当前平台原生字长相同的无符号整数。除了这种情况,最好使用`Int`,即使你要存储的值已知是非负的。统一使用`Int`可以提高代码的可复用性,避免不同类型数字之间的转换,并且匹配数字的类型推断,请参考[类型安全和类型推断](#type_safety_and_type_inference)。
@@ -253,15 +259,15 @@ Swift 也提供了一个特殊的无符号类型`UInt`,长度与当前平台
## 浮点数
-浮点数是有小数部分的数字,比如`3.14159`,`0.1`和`-273.15`。
+浮点数是有小数部分的数字,比如 `3.14159` ,`0.1` 和 `-273.15`。
-浮点类型比整数类型表示的范围更大,可以存储比`Int`类型更大或者更小的数字。Swift 提供了两种有符号浮点数类型:
+浮点类型比整数类型表示的范围更大,可以存储比 `Int` 类型更大或者更小的数字。Swift 提供了两种有符号浮点数类型:
* `Double`表示64位浮点数。当你需要存储很大或者很高精度的浮点数时请使用此类型。
* `Float`表示32位浮点数。精度要求不高的话可以使用此类型。
> 注意:
-`Double`精确度很高,至少有15位数字,而`Float`只有6位数字。选择哪个类型取决于你的代码需要处理的值的范围。
+`Double`精确度很高,至少有15位数字,而`Float`只有6位数字。选择哪个类型取决于你的代码需要处理的值的范围,在两种类型都匹配的情况下,将优先选择 `Double`。
## 类型安全和类型推断
@@ -274,32 +280,32 @@ Swift 是一个*类型安全(type safe)*的语言。类型安全的语言可
因为有类型推断,和 C 或者 Objective-C 比起来 Swift 很少需要声明类型。常量和变量虽然需要明确类型,但是大部分工作并不需要你自己来完成。
-当你声明常量或者变量并赋初值的时候类型推断非常有用。当你在声明常量或者变量的时候赋给它们一个字面量(literal value 或 literal)即可触发类型推断。(字面量就是会直接出现在你代码中的值,比如`42`和`3.14159`。)
+当你声明常量或者变量并赋初值的时候类型推断非常有用。当你在声明常量或者变量的时候赋给它们一个字面量(literal value 或 literal)即可触发类型推断。(字面量就是会直接出现在你代码中的值,比如 `42` 和 `3.14159` 。)
-例如,如果你给一个新常量赋值`42`并且没有标明类型,Swift 可以推断出常量类型是`Int`,因为你给它赋的初始值看起来像一个整数:
+例如,如果你给一个新常量赋值 `42` 并且没有标明类型,Swift 可以推断出常量类型是 `Int` ,因为你给它赋的初始值看起来像一个整数:
```swift
let meaningOfLife = 42
// meaningOfLife 会被推测为 Int 类型
```
-同理,如果你没有给浮点字面量标明类型,Swift 会推断你想要的是`Double`:
+同理,如果你没有给浮点字面量标明类型,Swift 会推断你想要的是 `Double`:
```swift
let pi = 3.14159
// pi 会被推测为 Double 类型
```
-当推断浮点数的类型时,Swift 总是会选择`Double`而不是`Float`。
+当推断浮点数的类型时,Swift 总是会选择 `Double` 而不是`Float`。
-如果表达式中同时出现了整数和浮点数,会被推断为`Double`类型:
+如果表达式中同时出现了整数和浮点数,会被推断为 `Double` 类型:
```swift
let anotherPi = 3 + 0.14159
// anotherPi 会被推测为 Double 类型
```
-原始值`3`没有显式声明类型,而表达式中出现了一个浮点字面量,所以表达式会被推断为`Double`类型。
+原始值 `3` 没有显式声明类型,而表达式中出现了一个浮点字面量,所以表达式会被推断为 `Double` 类型。
## 数值型字面量
@@ -320,13 +326,15 @@ let octalInteger = 0o21 // 八进制的17
let hexadecimalInteger = 0x11 // 十六进制的17
```
-浮点字面量可以是十进制(没有前缀)或者是十六进制(前缀是`0x`)。小数点两边必须有至少一个十进制数字(或者是十六进制的数字)。十进制浮点数也可以有一个可选的指数(exponent),通过大写或者小写的 `e` 来指定;十六进制浮点数必须有一个指数,通过大写或者小写的 `p` 来指定。
+浮点字面量可以是十进制(没有前缀)或者是十六进制(前缀是 `0x` )。小数点两边必须有至少一个十进制数字(或者是十六进制的数字)。十进制浮点数也可以有一个可选的指数(exponent),通过大写或者小写的 `e` 来指定;十六进制浮点数必须有一个指数,通过大写或者小写的 `p` 来指定。
+
+如果一个十进制数的指数为 `exp`,那这个数相当于基数和10^exp的乘积:
-如果一个十进制数的指数为`exp`,那这个数相当于基数和10^exp的乘积:
* `1.25e2` 表示 1.25 × 10^2,等于 `125.0`。
* `1.25e-2` 表示 1.25 × 10^-2,等于 `0.0125`。
-如果一个十六进制数的指数为`exp`,那这个数相当于基数和2^exp的乘积:
+如果一个十六进制数的指数为`exp`,那这个数相当于基数和2^exp的乘积:
+
* `0xFp2` 表示 15 × 2^2,等于 `60.0`。
* `0xFp-2` 表示 15 × 2^-2,等于 `3.75`。
@@ -375,9 +383,9 @@ let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)
```
-现在两个数字的类型都是`UInt16`,可以进行相加。目标常量`twoThousandAndOne`的类型被推断为`UInt16`,因为它是两个`UInt16`值的和。
+现在两个数字的类型都是 `UInt16`,可以进行相加。目标常量 `twoThousandAndOne` 的类型被推断为 `UInt16`,因为它是两个 `UInt16` 值的和。
-`SomeType(ofInitialValue)`是调用 Swift 构造器并传入一个初始值的默认方法。在语言内部,`UInt16`有一个构造器,可以接受一个`UInt8`类型的值,所以这个构造器可以用现有的`UInt8`来创建一个新的`UInt16`。注意,你并不能传入任意类型的值,只能传入`UInt16`内部有对应构造器的值。不过你可以扩展现有的类型来让它可以接收其他类型的值(包括自定义类型),请参考[扩展](./20_Extensions.html)。
+`SomeType(ofInitialValue)` 是调用 Swift 构造器并传入一个初始值的默认方法。在语言内部,`UInt16` 有一个构造器,可以接受一个`UInt8`类型的值,所以这个构造器可以用现有的 `UInt8` 来创建一个新的 `UInt16`。注意,你并不能传入任意类型的值,只能传入 `UInt16` 内部有对应构造器的值。不过你可以扩展现有的类型来让它可以接收其他类型的值(包括自定义类型),请参考[扩展](./20_Extensions.html)。
### 整数和浮点数转换
@@ -391,16 +399,16 @@ let pi = Double(three) + pointOneFourOneFiveNine
// pi 等于 3.14159,所以被推测为 Double 类型
```
-这个例子中,常量`three`的值被用来创建一个`Double`类型的值,所以加号两边的数类型须相同。如果不进行转换,两者无法相加。
+这个例子中,常量 `three` 的值被用来创建一个 `Double` 类型的值,所以加号两边的数类型须相同。如果不进行转换,两者无法相加。
-浮点数到整数的反向转换同样行,整数类型可以用`Double`或者`Float`类型来初始化:
+浮点数到整数的反向转换同样行,整数类型可以用 `Double` 或者 `Float` 类型来初始化:
```swift
let integerPi = Int(pi)
// integerPi 等于 3,所以被推测为 Int 类型
```
-当用这种方式来初始化一个新的整数值时,浮点值会被截断。也就是说`4.75`会变成`4`,`-3.9`会变成`-3`。
+当用这种方式来初始化一个新的整数值时,浮点值会被截断。也就是说 `4.75` 会变成 `4`,`-3.9` 会变成 `-3`。
> 注意:
结合数字类常量和变量不同于结合数字类字面量。字面量`3`可以直接和字面量`0.14159`相加,因为数字字面量本身没有明确的类型。它们的类型只在编译器需要求值的时候被推测。
@@ -428,16 +436,16 @@ var maxAmplitudeFound = AudioSample.min
## 布尔值
-Swift 有一个基本的布尔(Boolean)类型,叫做`Bool`。布尔值指逻辑上的值,因为它们只能是真或者假。Swift 有两个布尔常量,`true`和`false`:
+Swift 有一个基本的布尔(Boolean)类型,叫做`Bool`。布尔值指逻辑上的值,因为它们只能是真或者假。Swift 有两个布尔常量,`true` 和 `false`:
```swift
let orangesAreOrange = true
let turnipsAreDelicious = false
```
-`orangesAreOrange`和`turnipsAreDelicious`的类型会被推断为`Bool`,因为它们的初值是布尔字面量。就像之前提到的`Int`和`Double`一样,如果你创建变量的时候给它们赋值`true`或者`false`,那你不需要将常量或者变量声明为`Bool`类型。初始化常量或者变量的时候如果所赋的值类型已知,就可以触发类型推断,这让 Swift 代码更加简洁并且可读性更高。
+`orangesAreOrange` 和 `turnipsAreDelicious` 的类型会被推断为 `Bool`,因为它们的初值是布尔字面量。就像之前提到的 `Int` 和 `Double` 一样,如果你创建变量的时候给它们赋值 `true` 或者 `false`,那你不需要将常量或者变量声明为 `Bool` 类型。初始化常量或者变量的时候如果所赋的值类型已知,就可以触发类型推断,这让 Swift 代码更加简洁并且可读性更高。
-当你编写条件语句比如`if`语句的时候,布尔值非常有用:
+当你编写条件语句比如 `if` 语句的时候,布尔值非常有用:
```swift
if turnipsAreDelicious {
@@ -450,7 +458,7 @@ if turnipsAreDelicious {
条件语句,例如`if`,请参考[控制流](./05_Control_Flow.html)。
-如果你在需要使用`Bool`类型的地方使用了非布尔值,Swift 的类型安全机制会报错。下面的例子会报告一个编译时错误:
+如果你在需要使用 `Bool` 类型的地方使用了非布尔值,Swift 的类型安全机制会报错。下面的例子会报告一个编译时错误:
```swift
let i = 1
@@ -468,7 +476,7 @@ if i == 1 {
}
```
-`i == 1`的比较结果是`Bool`类型,所以第二个例子可以通过类型检查。类似`i == 1`这样的比较,请参考[基本操作符](./05_Control_Flow.html)。
+`i == 1` 的比较结果是 `Bool` 类型,所以第二个例子可以通过类型检查。类似 `i == 1` 这样的比较,请参考[基本操作符](./05_Control_Flow.html)。
和 Swift 中的其他类型安全的例子一样,这个方法可以避免错误并保证这块代码的意图总是清晰的。
@@ -477,16 +485,16 @@ if i == 1 {
*元组(tuples)*把多个值组合成一个复合值。元组内的值可以是任意类型,并不要求是相同类型。
-下面这个例子中,`(404, "Not Found")`是一个描述 *HTTP 状态码(HTTP status code)*的元组。HTTP 状态码是当你请求网页的时候 web 服务器返回的一个特殊值。如果你请求的网页不存在就会返回一个`404 Not Found`状态码。
+下面这个例子中,`(404, "Not Found")` 是一个描述 *HTTP 状态码(HTTP status code)*的元组。HTTP 状态码是当你请求网页的时候 web 服务器返回的一个特殊值。如果你请求的网页不存在就会返回一个 `404 Not Found` 状态码。
```swift
let http404Error = (404, "Not Found")
// http404Error 的类型是 (Int, String),值是 (404, "Not Found")
```
-`(404, "Not Found")`元组把一个`Int`值和一个`String`值组合起来表示 HTTP 状态码的两个部分:一个数字和一个人类可读的描述。这个元组可以被描述为“一个类型为`(Int, String)`的元组”。
+`(404, "Not Found")` 元组把一个 `Int` 值和一个 `String` 值组合起来表示 HTTP 状态码的两个部分:一个数字和一个人类可读的描述。这个元组可以被描述为“一个类型为 `(Int, String)` 的元组”。
-你可以把任意顺序的类型组合成一个元组,这个元组可以包含所有类型。只要你想,你可以创建一个类型为`(Int, Int, Int)`或者`(String, Bool)`或者其他任何你想要的组合的元组。
+你可以把任意顺序的类型组合成一个元组,这个元组可以包含所有类型。只要你想,你可以创建一个类型为 `(Int, Int, Int)` 或者 `(String, Bool)` 或者其他任何你想要的组合的元组。
你可以将一个元组的内容分解(decompose)成单独的常量和变量,然后你就可以正常使用它们了:
@@ -530,7 +538,7 @@ print("The status message is \(http200Status.description)")
// 输出 "The status message is OK"
```
-作为函数返回值时,元组非常有用。一个用来获取网页的函数可能会返回一个`(Int, String)`元组来描述是否获取成功。和只能返回一个类型的值比较起来,一个包含两个不同类型值的元组可以让函数的返回信息更有用。请参考[函数参数与返回值](./06_Functions.html#Function_Parameters_and_Return_Values)。
+作为函数返回值时,元组非常有用。一个用来获取网页的函数可能会返回一个 `(Int, String)` 元组来描述是否获取成功。和只能返回一个类型的值比较起来,一个包含两个不同类型值的元组可以让函数的返回信息更有用。请参考[函数参数与返回值](./06_Functions.html#Function_Parameters_and_Return_Values)。
> 注意:
元组在临时组织值的时候很有用,但是并不适合创建复杂的数据结构。如果你的数据结构并不是临时使用,请使用类或者结构体而不是元组。请参考[类和结构体](./09_Classes_and_Structures.html)。
@@ -547,11 +555,11 @@ print("The status message is \(http200Status.description)")
* 没有值
> 注意:
-C 和 Objective-C 中并没有可选类型这个概念。最接近的是 Objective-C 中的一个特性,一个方法要不返回一个对象要不返回`nil`,`nil`表示“缺少一个合法的对象”。然而,这只对对象起作用——对于结构体,基本的 C 类型或者枚举类型不起作用。对于这些类型,Objective-C 方法一般会返回一个特殊值(比如`NSNotFound`)来暗示值缺失。这种方法假设方法的调用者知道并记得对特殊值进行判断。然而,Swift 的可选类型可以让你暗示_任意类型_的值缺失,并不需要一个特殊值。
+C 和 Objective-C 中并没有可选类型这个概念。最接近的是 Objective-C 中的一个特性,一个方法要不返回一个对象要不返回`nil`,`nil`表示“缺少一个合法的对象”。然而,这只对对象起作用——对于结构体,基本的 C 类型或者枚举类型不起作用。对于这些类型,Objective-C 方法一般会返回一个特殊值(比如`NSNotFound`)来暗示值缺失。这种方法假设方法的调用者知道并记得对特殊值进行判断。然而,Swift 的可选类型可以让你暗示*任意类型*的值缺失,并不需要一个特殊值。
-来看一个例子。Swift 的`Int`类型有一种构造器,作用是将一个`String`值转换成一个`Int`值。然而,并不是所有的字符串都可以转换成一个整数。字符串`"123"`可以被转换成数字`123`,但是字符串`"hello, world"`不行。
+来看一个例子。Swift 的 `Int` 类型有一种构造器,作用是将一个 `String` 值转换成一个 `Int` 值。然而,并不是所有的字符串都可以转换成一个整数。字符串 `"123"` 可以被转换成数字 `123` ,但是字符串 `"hello, world"` 不行。
-下面的例子使用这种构造器来尝试将一个`String`转换成`Int`:
+下面的例子使用这种构造器来尝试将一个 `String` 转换成 `Int`:
```swift
let possibleNumber = "123"
@@ -559,7 +567,7 @@ let convertedNumber = Int(possibleNumber)
// convertedNumber 被推测为类型 "Int?", 或者类型 "optional Int"
```
-因为该构造器可能会失败,所以它返回一个_可选类型_(optional)`Int`,而不是一个`Int`。一个可选的`Int`被写作`Int?`而不是`Int`。问号暗示包含的值是可选类型,也就是说可能包含`Int`值也可能*不包含值*。(不能包含其他任何值比如`Bool`值或者`String`值。只能是`Int`或者什么都没有。)
+因为该构造器可能会失败,所以它返回一个*可选类型*(optional)`Int`,而不是一个 `Int`。一个可选的 `Int` 被写作 `Int?` 而不是 `Int`。问号暗示包含的值是可选类型,也就是说可能包含 `Int` 值也可能*不包含值*。(不能包含其他任何值比如 `Bool` 值或者 `String` 值。只能是 `Int` 或者什么都没有。)
### nil
@@ -576,7 +584,7 @@ serverResponseCode = nil
> 注意:
`nil`不能用于非可选的常量和变量。如果你的代码中有常量或者变量需要处理值缺失的情况,请把它们声明成对应的可选类型。
-如果你声明一个可选常量或者变量但是没有赋值,它们会自动被设置为`nil`:
+如果你声明一个可选常量或者变量但是没有赋值,它们会自动被设置为 `nil`:
```swift
var surveyAnswer: String?
@@ -584,22 +592,23 @@ var surveyAnswer: String?
```
> 注意:
-Swift 的`nil`和 Objective-C 中的`nil`并不一样。在 Objective-C 中,`nil`是一个指向不存在对象的指针。在 Swift 中,`nil`不是指针——它是一个确定的值,用来表示值缺失。任何类型的可选状态都可以被设置为`nil`,不只是对象类型。
+Swift 的 `nil` 和 Objective-C 中的 `nil` 并不一样。在 Objective-C 中,`nil` 是一个指向不存在对象的指针。在 Swift 中,`nil` 不是指针——它是一个确定的值,用来表示值缺失。任何类型的可选状态都可以被设置为 `nil`,不只是对象类型。
### if 语句以及强制解析
-你可以使用`if`语句和`nil`比较来判断一个可选值是否包含值。你可以使用“相等”(`==`)或“不等”(`!=`)来执行比较。
+你可以使用 `if` 语句和 `nil` 比较来判断一个可选值是否包含值。你可以使用“相等”(`==`)或“不等”(`!=`)来执行比较。
-如果可选类型有值,它将不等于`nil`:
+如果可选类型有值,它将不等于 `nil`:
```swift
if convertedNumber != nil {
print("convertedNumber contains some integer value.")
}
// 输出 "convertedNumber contains some integer value."
-```
-当你确定可选类型确实包含值之后,你可以在可选的名字后面加一个感叹号(`!`)来获取值。这个惊叹号表示“我知道这个可选有值,请使用它。”这被称为可选值的_强制解析(forced unwrapping)_:
+```
+
+当你确定可选类型确实包含值之后,你可以在可选的名字后面加一个感叹号(`!`)来获取值。这个惊叹号表示“我知道这个可选有值,请使用它。”这被称为可选值的*强制解析(forced unwrapping)*:
```swift
if convertedNumber != nil {
@@ -608,17 +617,17 @@ if convertedNumber != nil {
// 输出 "convertedNumber has an integer value of 123."
```
-更多关于`if`语句的内容,请参考[控制流](05_Control_Flow.html)。
+更多关于 `if` 语句的内容,请参考[控制流](05_Control_Flow.html)。
> 注意:
-使用`!`来获取一个不存在的可选值会导致运行时错误。使用`!`来强制解析值之前,一定要确定可选包含一个非`nil`的值。
+使用 `!` 来获取一个不存在的可选值会导致运行时错误。使用 `!` 来强制解析值之前,一定要确定可选包含一个非 `nil` 的值。
### 可选绑定
-使用*可选绑定(optional binding)*来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。可选绑定可以用在`if`和`while`语句中,这条语句不仅可以用来判断可选类型中是否有值,同时可以将可选类型中的值赋给一个常量或者变量。`if`和`while`语句,请参考[控制流](./05_Control_Flow.html)。
+使用*可选绑定(optional binding)*来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。可选绑定可以用在 `if` 和 `while` 语句中,这条语句不仅可以用来判断可选类型中是否有值,同时可以将可选类型中的值赋给一个常量或者变量。`if` 和 `while` 语句,请参考[控制流](./05_Control_Flow.html)。
-像下面这样在`if`语句中写一个可选绑定:
+像下面这样在 `if` 语句中写一个可选绑定:
```swift
if let constantName = someOptional {
@@ -626,7 +635,7 @@ if let constantName = someOptional {
}
```
-你可以像上面这样使用可选绑定来重写`possibleNumber`这个[例子](./01_The_Basics.html#optionals):
+你可以像上面这样使用可选绑定来重写 `possibleNumber` 这个[例子](./01_The_Basics.html#optionals):
```swift
if let actualNumber = Int(possibleNumber) {
@@ -639,25 +648,37 @@ if let actualNumber = Int(possibleNumber) {
这段代码可以被理解为:
-“如果`Int(possibleNumber)`返回的可选`Int`包含一个值,创建一个叫做`actualNumber`的新常量并将可选包含的值赋给它。”
+“如果 `Int(possibleNumber)` 返回的可选 `Int` 包含一个值,创建一个叫做 `actualNumber` 的新常量并将可选包含的值赋给它。”
-如果转换成功,`actualNumber`常量可以在`if`语句的第一个分支中使用。它已经被可选类型 _包含的_ 值初始化过,所以不需要再使用`!`后缀来获取它的值。在这个例子中,`actualNumber`只被用来输出转换结果。
+如果转换成功,`actualNumber` 常量可以在 `if` 语句的第一个分支中使用。它已经被可选类型 *包含的* 值初始化过,所以不需要再使用 `!` 后缀来获取它的值。在这个例子中,`actualNumber` 只被用来输出转换结果。
-你可以在可选绑定中使用常量和变量。如果你想在`if`语句的第一个分支中操作`actualNumber`的值,你可以改成`if var actualNumber`,这样可选类型包含的值就会被赋给一个变量而非常量。
+你可以在可选绑定中使用常量和变量。如果你想在`if`语句的第一个分支中操作 `actualNumber` 的值,你可以改成 `if var actualNumber`,这样可选类型包含的值就会被赋给一个变量而非常量。
-你可以包含多个可选绑定在`if`语句中,并使用`where`子句做布尔值判断。
+你可以包含多个可选绑定或多个布尔条件在一个 `if` 语句中,只要使用逗号分开就行。如果所有可选绑定的值为 `nil` 或者所有布尔条件语句都为 `false`,这样整个 `if` 条件判断都是为 `false`,这时你就需要使用嵌套 `if` 条件语句来处理,如下所示:
```swift
-if let firstNumber = Int("4"), secondNumber = Int("42") where firstNumber < secondNumber {
- print("\(firstNumber) < \(secondNumber)")
-}
-// prints "4 < 42"
-```
+if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
+ print("\(firstNumber) < \(secondNumber) < 100")
+}
+// Prints "4 < 42 < 100"
+
+if let firstNumber = Int("4") {
+ if let secondNumber = Int("42") {
+ if firstNumber < secondNumber && secondNumber < 100 {
+ print("\(firstNumber) < \(secondNumber) < 100")
+ }
+ }
+}
+// Prints "4 < 42 < 100"
+```
+
+> 注意:
+> 在 `if` 条件语句中使用常量和变量来创建一个可选绑定,仅在 `if` 语句的句中(`body`)中才能获取到值。相反,在 `guard` 语句中使用常量和变量来创建一个可选绑定,仅在 `guard` 语句外且在语句后才能获取到值,请参考[控制流](./05_Control_Flow#early_exit.html)。
### 隐式解析可选类型
-如上所述,可选类型暗示了常量或者变量可以“没有值”。可选可以通过`if`语句来判断是否有值,如果有值的话可以通过可选绑定来解析值。
+如上所述,可选类型暗示了常量或者变量可以“没有值”。可选可以通过 `if` 语句来判断是否有值,如果有值的话可以通过可选绑定来解析值。
有时候在程序架构中,第一次被赋值之后,可以确定一个可选类型_总会_有值。在这种情况下,每次都要判断和解析可选值是非常低效的,因为可以确定它总会有值。
@@ -665,7 +686,7 @@ if let firstNumber = Int("4"), secondNumber = Int("42") where firstNumber < seco
当可选类型被第一次赋值之后就可以确定之后一直有值的时候,隐式解析可选类型非常有用。隐式解析可选类型主要被用在 Swift 中类的构造过程中,请参考[无主引用以及隐式解析可选属性](./16_Automatic_Reference_Counting.html#unowned_references_and_implicitly_unwrapped_optional_properties)。
-一个隐式解析可选类型其实就是一个普通的可选类型,但是可以被当做非可选类型来使用,并不需要每次都使用解析来获取可选值。下面的例子展示了可选类型`String`和隐式解析可选类型`String`之间的区别:
+一个隐式解析可选类型其实就是一个普通的可选类型,但是可以被当做非可选类型来使用,并不需要每次都使用解析来获取可选值。下面的例子展示了可选类型 `String` 和隐式解析可选类型 `String` 之间的区别:
```swift
let possibleString: String? = "An optional string."
@@ -678,7 +699,7 @@ let implicitString: String = assumedString // 不需要感叹号
你可以把隐式解析可选类型当做一个可以自动解析的可选类型。你要做的只是声明的时候把感叹号放到类型的结尾,而不是每次取值的可选名字的结尾。
> 注意:
-如果你在隐式解析可选类型没有值的时候尝试取值,会触发运行时错误。和你在没有值的普通可选类型后面加一个惊叹号一样。
+> 如果你在隐式解析可选类型没有值的时候尝试取值,会触发运行时错误。和你在没有值的普通可选类型后面加一个惊叹号一样。
你仍然可以把隐式解析可选类型当做普通可选类型来判断它是否包含值:
@@ -699,11 +720,11 @@ if let definiteString = assumedString {
```
> 注意:
-如果一个变量之后可能变成`nil`的话请不要使用隐式解析可选类型。如果你需要在变量的生命周期中判断是否是`nil`的话,请使用普通可选类型。
+> 如果一个变量之后可能变成`nil`的话请不要使用隐式解析可选类型。如果你需要在变量的生命周期中判断是否是`nil`的话,请使用普通可选类型。
## 错误处理
-你可以使用*错误处理(error handling)*来应对程序执行中可能会遇到的错误条件。
+你可以使用 *错误处理(error handling)* 来应对程序执行中可能会遇到的错误条件。
相对于可选中运用值的存在与缺失来表达函数的成功与失败,错误处理可以推断失败的原因,并传播至程序的其他部分。
@@ -731,38 +752,38 @@ do {
这里有一个错误处理如何用来应对不同错误条件的例子。
```swift
-func makeASandwich() throws {
- // ...
-}
-
-do {
- try makeASandwich()
- eatASandwich()
-} catch Error.OutOfCleanDishes {
- washDishes()
-} catch Error.MissingIngredients(let ingredients) {
- buyGroceries(ingredients)
+func makeASandwich() throws {
+ // ...
+}
+
+do {
+ try makeASandwich()
+ eatASandwich()
+} catch SandwichError.outOfCleanDishes {
+ washDishes()
+} catch SandwichError.missingIngredients(let ingredients) {
+ buyGroceries(ingredients)
}
```
-在此例中,`makeASandwich()`(做一个三明治)函数会抛出一个错误消息如果没有干净的盘子或者某个原料缺失。因为`makeASandwich()`抛出错误,函数调用被包裹在`try`表达式中。将函数包裹在一个`do`语句中,任何被抛出的错误会被传播到提供的`catch`从句中。
+在此例中,`makeASandwich()`(做一个三明治)函数会抛出一个错误消息如果没有干净的盘子或者某个原料缺失。因为 `makeASandwich()` 抛出错误,函数调用被包裹在 `try` 表达式中。将函数包裹在一个 `do` 语句中,任何被抛出的错误会被传播到提供的 `catch` 从句中。
-如果没有错误被抛出, `eatASandwich()`函数会被调用。如果一个匹配`Error.OutOfCleanDishes`的错误被抛出,`washDishes`函数会被调用。如果一个匹配`Error.MissingIngredients`的错误被抛出,`buyGroceries(_:)`函数会被调用,并且使用`catch`所捕捉到的关联值`[String]`作为参数。
+如果没有错误被抛出,`eatASandwich()` 函数会被调用。如果一个匹配 `SandwichError.outOfCleanDishes` 的错误被抛出,`washDishes()` 函数会被调用。如果一个匹配 `SandwichError.missingIngredients` 的错误被抛出,`buyGroceries(_:)` 函数会被调用,并且使用 `catch` 所捕捉到的关联值 `[String]` 作为参数。
抛出,捕捉,以及传播错误会在[错误处理](./18_Error_Handling.html)章节详细说明。
## 断言
-可选类型可以让你判断值是否存在,你可以在代码中优雅地处理值缺失的情况。然而,在某些情况下,如果值缺失或者值并不满足特定的条件,你的代码可能没办法继续执行。这时,你可以在你的代码中触发一个*断言(assertion)*来结束代码运行并通过调试来找到值缺失的原因。
+可选类型可以让你判断值是否存在,你可以在代码中优雅地处理值缺失的情况。然而,在某些情况下,如果值缺失或者值并不满足特定的条件,你的代码可能没办法继续执行。这时,你可以在你的代码中触发一个 *断言(assertion)* 来结束代码运行并通过调试来找到值缺失的原因。
### 使用断言进行调试
-断言会在运行时判断一个逻辑条件是否为`true`。从字面意思来说,断言“断言”一个条件是否为真。你可以使用断言来保证在运行其他代码之前,某些重要的条件已经被满足。如果条件判断为`true`,代码运行会继续进行;如果条件判断为`false`,代码执行结束,你的应用被终止。
+断言会在运行时判断一个逻辑条件是否为 `true`。从字面意思来说,断言“断言”一个条件是否为真。你可以使用断言来保证在运行其他代码之前,某些重要的条件已经被满足。如果条件判断为 `true`,代码运行会继续进行;如果条件判断为 `false`,代码执行结束,你的应用被终止。
如果你的代码在调试环境下触发了一个断言,比如你在 Xcode 中构建并运行一个应用,你可以清楚地看到不合法的状态发生在哪里并检查断言被触发时你的应用的状态。此外,断言允许你附加一条调试信息。
-你可以使用全局`assert(_:_:file:line:)`函数来写一个断言。向这个函数传入一个结果为`true`或者`false`的表达式以及一条信息,当表达式的结果为`false`的时候这条信息会被显示:
+你可以使用全局 `assert(_:_:file:line:)` 函数来写一个断言。向这个函数传入一个结果为 `true` 或者 `false` 的表达式以及一条信息,当表达式的结果为 `false` 的时候这条信息会被显示:
```swift
let age = -3
@@ -770,7 +791,7 @@ assert(age >= 0, "A person's age cannot be less than zero")
// 因为 age < 0,所以断言会触发
```
-在这个例子中,只有`age >= 0`为`true`的时候,即`age`的值非负的时候,代码才会继续执行。如果`age`的值是负数,就像代码中那样,`age >= 0`为`false`,断言被触发,终止应用。
+在这个例子中,只有 `age >= 0` 为 `true` 的时候,即 `age` 的值非负的时候,代码才会继续执行。如果 `age` 的值是负数,就像代码中那样,`age >= 0` 为 `false`,断言被触发,终止应用。
如果不需要断言信息,可以省略,就像这样:
@@ -779,7 +800,7 @@ assert(age >= 0)
```
> 注意:
-当代码使用优化编译的时候,断言将会被禁用,例如在 Xcode 中,使用默认的 target Release 配置选项来 build 时,断言会被禁用。
+> 当代码使用优化编译的时候,断言将会被禁用,例如在 Xcode 中,使用默认的 target Release 配置选项来 build 时,断言会被禁用。
### 何时使用断言
@@ -787,11 +808,9 @@ assert(age >= 0)
* 整数类型的下标索引被传入一个自定义下标实现,但是下标索引值可能太小或者太大。
* 需要给函数传入一个值,但是非法的值可能导致函数不能正常执行。
-* 一个可选值现在是`nil`,但是后面的代码运行需要一个非`nil`值。
+* 一个可选值现在是 `nil`,但是后面的代码运行需要一个非 `nil` 值。
请参考[下标](./12_Subscripts.html)和[函数](./06_Functions.html)。
> 注意:
-断言可能导致你的应用终止运行,所以你应当仔细设计你的代码来让非法条件不会出现。然而,在你的应用发布之前,有时候非法条件可能出现,这时使用断言可以快速发现问题。
-
-
+> 断言可能导致你的应用终止运行,所以你应当仔细设计你的代码来让非法条件不会出现。然而,在你的应用发布之前,有时候非法条件可能出现,这时使用断言可以快速发现问题。
diff --git a/source/chapter2/03_Strings_and_Characters.md b/source/chapter2/03_Strings_and_Characters.md
index d13f4a99..12c31586 100755
--- a/source/chapter2/03_Strings_and_Characters.md
+++ b/source/chapter2/03_Strings_and_Characters.md
@@ -17,6 +17,8 @@
> 3.0
> 校对:[CMB](https://github.com/chenmingbiao)
+>
+> 版本日期:2016-09-13
本页包含内容:
From 64dd00b6f652ca18704103d06f785d9f286cb6f4 Mon Sep 17 00:00:00 2001
From: Cai Linfeng
Date: Sat, 17 Sep 2016 22:11:29 +0800
Subject: [PATCH 05/32] update chapter 'Closure' to swift 3.0
---
source/chapter2/07_Closures.md | 211 ++++++++++++++++-----------------
1 file changed, 104 insertions(+), 107 deletions(-)
diff --git a/source/chapter2/07_Closures.md b/source/chapter2/07_Closures.md
index 3a5ebf9b..c2b6c9db 100755
--- a/source/chapter2/07_Closures.md
+++ b/source/chapter2/07_Closures.md
@@ -21,15 +21,15 @@
- [尾随闭包(Trailing Closures)](#trailing_closures)
- [值捕获(Capturing Values)](#capturing_values)
- [闭包是引用类型(Closures Are Reference Types)](#closures_are_reference_types)
-- [非逃逸闭包(Nonescaping Closures) ](#nonescaping_closures)
+- [逃逸闭包(Escaping Closures) ](#escaping_closures)
- [自动闭包(Autoclosures)](#autoclosures)
-闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的匿名函数比较相似。
+*闭包*是自包含的函数代码块,可以在代码中被传递和使用。Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的匿名函数比较相似。
-闭包可以捕获和存储其所在上下文中任意常量和变量的引用。这就是所谓的闭合并包裹着这些常量和变量,俗称闭包。Swift 会为您管理在捕获过程中涉及到的所有内存操作。
+闭包可以捕获和存储其所在上下文中任意常量和变量的引用。*闭合、包裹*常量和变量,所谓闭包也。Swift 会为你管理在捕获过程中涉及到的所有内存操作。
> 注意
-> 如果您不熟悉捕获(capturing)这个概念也不用担心,您可以在[值捕获](#capturing_values)章节对其进行详细了解。
+> 如果你不熟悉捕获(capturing)这个概念也不用担心,你可以在[值捕获](#capturing_values)章节对其进行详细了解。
在[函数](./06_Functions.html)章节中介绍的全局和嵌套函数实际上也是特殊的闭包,闭包采取如下三种形式之一:
@@ -48,43 +48,43 @@ Swift 的闭包表达式拥有简洁的风格,并鼓励在常见场景中进
## 闭包表达式(Closure Expressions)
-[嵌套函数](./06_Functions.html#nested_function)是一个在较复杂函数中方便进行命名和定义自包含代码模块的方式。当然,有时候撰写小巧的没有完整定义和命名的类函数结构也是很有用处的,尤其是在您处理一些函数并需要将另外一些函数作为该函数的参数时。
+[嵌套函数](./06_Functions.html#nested_function)是一个在较复杂函数中方便进行命名和定义自包含代码模块的方式。当然,有时候编写小巧的没有完整定义和命名的类函数结构也是很有用处的,尤其是在你处理一些函数并需要将另外一些函数作为该函数的参数时。
-闭包表达式是一种利用简洁语法构建内联闭包的方式。闭包表达式提供了一些语法优化,使得撰写闭包变得简单明了。下面闭包表达式的例子通过使用几次迭代展示了`sort(_:)`方法定义和语法优化的方式。每一次迭代都用更简洁的方式描述了相同的功能。
+*闭包表达式*是一种利用简洁语法构建内联闭包的方式。闭包表达式提供了一些语法优化,使得撰写闭包变得简单明了。下面闭包表达式的例子通过使用几次迭代展示了`sorted(by:)`方法定义和语法优化的方式。每一次迭代都用更简洁的方式描述了相同的功能。
-### sort 方法(The Sort Method)
+### sorted 方法(The Sorted Method)
-Swift 标准库提供了名为`sort`的方法,会根据您提供的用于排序的闭包函数将已知类型数组中的值进行排序。一旦排序完成,`sort(_:)`方法会返回一个与原数组大小相同,包含同类型元素且元素已正确排序的新数组。原数组不会被`sort(_:)`方法修改。
+Swift 标准库提供了名为`sorted(by:)`的方法,会根据你所提供的用于排序的闭包函数将已知类型数组中的值进行排序。一旦排序完成,`sorted(by:)`方法会返回一个与原数组大小相同,包含同类型元素且元素已正确排序的新数组。原数组不会被`sorted(by:)`方法修改。
-下面的闭包表达式示例使用`sort(_:)`方法对一个`String`类型的数组进行字母逆序排序.以下是初始数组值:
+下面的闭包表达式示例使用`sorted(by:)`方法对一个`String`类型的数组进行字母逆序排序.以下是初始数组值:
```swift
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
```
-`sort(_:)`方法接受一个闭包,该闭包函数需要传入与数组元素类型相同的两个值,并返回一个布尔类型值来表明当排序结束后传入的第一个参数排在第二个参数前面还是后面。如果第一个参数值出现在第二个参数值前面,排序闭包函数需要返回`true`,反之返回`false`。
+`sorted(by:)`方法接受一个闭包,该闭包函数需要传入与数组元素类型相同的两个值,并返回一个布尔类型值来表明当排序结束后传入的第一个参数排在第二个参数前面还是后面。如果第一个参数值出现在第二个参数值*前面*,排序闭包函数需要返回`true`,反之返回`false`。
该例子对一个`String`类型的数组进行排序,因此排序闭包函数类型需为`(String, String) -> Bool`。
-提供排序闭包函数的一种方式是撰写一个符合其类型要求的普通函数,并将其作为`sort(_:)`方法的参数传入:
+提供排序闭包函数的一种方式是撰写一个符合其类型要求的普通函数,并将其作为`sorted(by:)`方法的参数传入:
```swift
-func backwards(s1: String, s2: String) -> Bool {
+func backward(_ s1: String, _ s2: String) -> Bool {
return s1 > s2
}
-var reversed = names.sort(backwards)
-// reversed 为 ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
+var reversedNames = names.sorted(by: backward)
+// reversedNames 为 ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
```
-如果第一个字符串(`s1`)大于第二个字符串(`s2`),`backwards(_:_:)`函数返回`true`,表示在新的数组中`s1`应该出现在`s2`前。对于字符串中的字符来说,“大于”表示“按照字母顺序较晚出现”。这意味着字母`"B"`大于字母`"A"`,字符串`"Tom"`大于字符串`"Tim"`。该闭包将进行字母逆序排序,`"Barry"`将会排在`"Alex"`之前。
+如果第一个字符串(`s1`)大于第二个字符串(`s2`),`backward(_:_:)`函数会返回`true`,表示在新的数组中`s1`应该出现在`s2`前。对于字符串中的字符来说,“大于”表示“按照字母顺序较晚出现”。这意味着字母`"B"`大于字母`"A"`,字符串`"Tom"`大于字符串`"Tim"`。该闭包将进行字母逆序排序,`"Barry"`将会排在`"Alex"`之前。
-然而,这是一个相当冗长的方式,本质上只是写了一个单表达式函数 (`a > b`)。在下面的例子中,利用闭包表达式语法可以更好地构造一个内联排序闭包。
+然而,以这种方式来编写一个实际上很简单的表达式(`a > b`),确实太过繁琐了。对于这个例子来说,利用闭包表达式语法可以更好地构造一个内联排序闭包。
### 闭包表达式语法(Closure Expression Syntax)
-闭包表达式语法有如下一般形式:
+闭包表达式语法有如下的一般形式:
```swift
{ (parameters) -> returnType in
@@ -92,41 +92,41 @@ var reversed = names.sort(backwards)
}
```
-闭包表达式语法可以使用常量、变量和`inout`类型作为参数,不能提供默认值。也可以在参数列表的最后使用可变参数。元组也可以作为参数和返回值。
+// MARK:
+闭包表达式的参数可以使inout参数,但不能设定默认值。也可以使用具名的可变参数。元组也可以作为参数和返回值。
-下面的例子展示了之前`backwards(_:_:)`函数对应的闭包表达式版本的代码:
+下面的例子展示了之前`backward(_:_:)`函数对应的闭包表达式版本的代码:
```swift
-reversed = names.sort({ (s1: String, s2: String) -> Bool in
+reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
})
```
-需要注意的是内联闭包参数和返回值类型声明与`backwards(_:_:)`函数类型声明相同。在这两种方式中,都写成了`(s1: String, s2: String) -> Bool`。然而在内联闭包表达式中,函数和返回值类型都写在大括号内,而不是大括号外。
+需要注意的是内联闭包参数和返回值类型声明与`backward(_:_:)`函数类型声明相同。在这两种方式中,都写成了`(s1: String, s2: String) -> Bool`。然而在内联闭包表达式中,函数和返回值类型都写在*大括号内*,而不是大括号外。
闭包的函数体部分由关键字`in`引入。该关键字表示闭包的参数和返回值类型定义已经完成,闭包函数体即将开始。
由于这个闭包的函数体部分如此短,以至于可以将其改写成一行代码:
```swift
-reversed = names.sort( { (s1: String, s2: String) -> Bool in return s1 > s2 } )
+reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } )
```
-该例中`sort(_:)`方法的整体调用保持不变,一对圆括号仍然包裹住了方法的整个参数。然而,参数现在变成了内联闭包。
+该例中`sorted(by:)`方法的整体调用保持不变,一对圆括号仍然包裹住了方法的整个参数。然而,参数现在变成了内联闭包。
### 根据上下文推断类型(Inferring Type From Context)
-因为排序闭包函数是作为`sort(_:)`方法的参数传入的,Swift 可以推断其参数和返回值的类型。`sort(_:)`方法被一个字符串数组调用,因此其参数必须是`(String, String) -> Bool`类型的函数。这意味着`(String, String)`和`Bool`类型并不需要作为闭包表达式定义的一部分。因为所有的类型都可以被正确推断,返回箭头(`->`)和围绕在参数周围的括号也可以被省略:
+因为排序闭包函数是作为`sorted(by:)`方法的参数传入的,Swift 可以推断其参数和返回值的类型。`sorted(by:)`方法被一个字符串数组调用,因此其参数必须是`(String, String) -> Bool`类型的函数。这意味着`(String, String)`和`Bool`类型并不需要作为闭包表达式定义的一部分。因为所有的类型都可以被正确推断,返回箭头(`->`)和围绕在参数周围的括号也可以被省略:
```swift
-reversed = names.sort( { s1, s2 in return s1 > s2 } )
+reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )
```
-实际上任何情况下,通过内联闭包表达式构造的闭包作为参数传递给函数或方法时,都可以推断出闭包的参数和返回值类型。
-这意味着闭包作为函数或者方法的参数时,您几乎不需要利用完整格式构造内联闭包。
+实际上,通过内联闭包表达式构造的闭包作为参数传递给函数或方法时,总是能够推断出闭包的参数和返回值类型。这意味着闭包作为函数或者方法的参数时,你几乎不需要利用完整格式构造内联闭包。
-尽管如此,您仍然可以明确写出有着完整格式的闭包。如果完整格式的闭包能够提高代码的可读性,则可以采用完整格式的闭包。而在`sort(_:)`方法这个例子里,闭包的目的就是排序。由于这个闭包是为了处理字符串数组的排序,因此读者能够推测出这个闭包是用于字符串处理的。
+尽管如此,你仍然可以明确写出有着完整格式的闭包。如果完整格式的闭包能够提高代码的可读性,则我们更鼓励采用完整格式的闭包。而在`sorted(by:)`方法这个例子里,显然闭包的目的就是排序。由于这个闭包是为了处理字符串数组的排序,因此读者能够推测出这个闭包是用于字符串处理的。
### 单表达式闭包隐式返回(Implicit Return From Single-Expression Clossures)
@@ -134,20 +134,20 @@ reversed = names.sort( { s1, s2 in return s1 > s2 } )
单行表达式闭包可以通过省略`return`关键字来隐式返回单行表达式的结果,如上版本的例子可以改写为:
```swift
-reversed = names.sort( { s1, s2 in s1 > s2 } )
+reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
```
-在这个例子中,`sort(_:)`方法的参数类型明确了闭包必须返回一个`Bool`类型值。因为闭包函数体只包含了一个单一表达式(`s1 > s2`),该表达式返回`Bool`类型值,因此这里没有歧义,`return`关键字可以省略。
+在这个例子中,`sorted(by:)`方法的参数类型明确了闭包必须返回一个`Bool`类型值。因为闭包函数体只包含了一个单一表达式(`s1 > s2`),该表达式返回`Bool`类型值,因此这里没有歧义,`return`关键字可以省略。
### 参数名称缩写(Shorthand Argument Names)
-Swift 自动为内联闭包提供了参数名称缩写功能,您可以直接通过`$0`,`$1`,`$2`来顺序调用闭包的参数,以此类推。
+Swift 自动为内联闭包提供了参数名称缩写功能,你可以直接通过`$0`,`$1`,`$2`来顺序调用闭包的参数,以此类推。
-如果您在闭包表达式中使用参数名称缩写,您可以在闭包参数列表中省略对其的定义,并且对应参数名称缩写的类型会通过函数类型进行推断。`in`关键字也同样可以被省略,因为此时闭包表达式完全由闭包函数体构成:
+如果你在闭包表达式中使用参数名称缩写,你可以在闭包定义中省略参数列表,并且对应参数名称缩写的类型会通过函数类型进行推断。`in`关键字也同样可以被省略,因为此时闭包表达式完全由闭包函数体构成:
```swift
-reversed = names.sort( { $0 > $1 } )
+reversedNames = names.sorted(by: { $0 > $1 } )
```
在这个例子中,`$0`和`$1`表示闭包中第一个和第二个`String`类型的参数。
@@ -155,10 +155,10 @@ reversed = names.sort( { $0 > $1 } )
### 运算符函数(Operator Functions)
-实际上还有一种更简短的方式来撰写上面例子中的闭包表达式。Swift 的`String`类型定义了关于大于号(`>`)的字符串实现,其作为一个函数接受两个`String`类型的参数并返回`Bool`类型的值。而这正好与`sort(_:)`方法的参数需要的函数类型相符合。因此,您可以简单地传递一个大于号,Swift 可以自动推断出您想使用大于号的字符串函数实现:
+实际上还有一种更简短的方式来编写上面例子中的闭包表达式。Swift 的`String`类型定义了关于大于号(`>`)的字符串实现,其作为一个函数接受两个`String`类型的参数并返回`Bool`类型的值。而这正好与`sorted(by:)`方法的参数需要的函数类型相符合。因此,你可以简单地传递一个大于号,Swift 可以自动推断出你想使用大于号的字符串函数实现:
```swift
-reversed = names.sort(>)
+reversedNames = names.sorted(by: >)
```
更多关于运算符表达式的内容请查看[运算符函数](./25_Advanced_Operators.html#operator_functions)。
@@ -166,7 +166,7 @@ reversed = names.sort(>)
## 尾随闭包(Trailing Closures)
-如果您需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用*尾随闭包*来增强函数的可读性。尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用:
+如果你需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用*尾随闭包*来增强函数的可读性。尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用:
```swift
func someFunctionThatTakesAClosure(closure: () -> Void) {
@@ -174,7 +174,7 @@ func someFunctionThatTakesAClosure(closure: () -> Void) {
}
// 以下是不使用尾随闭包进行函数调用
-someFunctionThatTakesAClosure({
+someFunctionThatTakesAClosure(closure: {
// 闭包主体部分
})
@@ -184,19 +184,19 @@ someFunctionThatTakesAClosure() {
}
```
-在[闭包表达式语法](#closure_expression_syntax)一节中作为`sort(_:)`方法参数的字符串排序闭包可以改写为:
+在[闭包表达式语法](#closure_expression_syntax)一节中作为`sorted(by:)`方法参数的字符串排序闭包可以改写为:
```swift
-reversed = names.sort() { $0 > $1 }
+reversedNames = names.sorted() { $0 > $1 }
```
-如果函数只需要闭包表达式一个参数,当您使用尾随闭包时,您甚至可以把`()`省略掉:
+如果闭包表达式是函数或方法的唯一参数,则当你使用尾随闭包时,你甚至可以把`()`省略掉:
```swift
-reversed = names.sort { $0 > $1 }
+reversedNames = names.sorted { $0 > $1 }
```
-当闭包非常长以至于不能在一行中进行书写时,尾随闭包变得非常有用。举例来说,Swift 的`Array`类型有一个`map(_:)`方法,其获取一个闭包表达式作为其唯一参数。该闭包函数会为数组中的每一个元素调用一次,并返回该元素所映射的值。具体的映射方式和返回值类型由闭包来指定。
+当闭包非常长以至于不能在一行中进行书写时,尾随闭包变得非常有用。举例来说,Swift 的`Array`类型有一个`map(_:)`方法,这个方法获取一个闭包表达式作为其唯一参数。该闭包函数会为数组中的每一个元素调用一次,并返回该元素所映射的值。具体的映射方式和返回值类型由闭包来指定。
当提供给数组的闭包应用于每个数组元素后,`map(_:)`方法将返回一个新的数组,数组中包含了与原数组中的元素一一对应的映射后的值。
@@ -210,44 +210,44 @@ let digitNames = [
let numbers = [16, 58, 510]
```
-如上代码创建了一个数字位和它们英文版本名字相映射的字典。同时还定义了一个准备转换为字符串数组的整型数组。
+如上代码创建了一个整型数位和它们英文版本名字相映射的字典。同时还定义了一个准备转换为字符串数组的整型数组。
-您现在可以通过传递一个尾随闭包给`numbers`的`map(_:)`方法来创建对应的字符串版本数组:
+你现在可以通过传递一个尾随闭包给`numbers`的`map(_:)`方法来创建对应的字符串版本数组:
```swift
let strings = numbers.map {
(number) -> String in
var number = number
var output = ""
- while number > 0 {
+ repeat {
output = digitNames[number % 10]! + output
number /= 10
- }
+ } while number > 0
return output
}
// strings 常量被推断为字符串类型数组,即 [String]
// 其值为 ["OneSix", "FiveEight", "FiveOneZero"]
```
-`map(_:)`为数组中每一个元素调用了闭包表达式。您不需要指定闭包的输入参数`number`的类型,因为可以通过要映射的数组类型进行推断。
+`map(_:)`为数组中每一个元素调用了一次闭包表达式。你不需要指定闭包的输入参数`number`的类型,因为可以通过要映射的数组类型进行推断。
在该例中,局部变量`number`的值由闭包中的`number`参数获得,因此可以在闭包函数体内对其进行修改,(闭包或者函数的参数总是常量),闭包表达式指定了返回类型为`String`,以表明存储映射值的新数组类型为`String`。
-闭包表达式在每次被调用的时候创建了一个叫做`output`的字符串并返回。其使用求余运算符(`number % 10`)计算最后一位数字并利用`digitNames`字典获取所映射的字符串。
+闭包表达式在每次被调用的时候创建了一个叫做`output`的字符串并返回。其使用求余运算符(`number % 10`)计算最后一位数字并利用`digitNames`字典获取所映射的字符串。这个闭包能够用于创建任意正整数的字符串表示。
> 注意
> 字典`digitNames`下标后跟着一个叹号(`!`),因为字典下标返回一个可选值(optional value),表明该键不存在时会查找失败。在上例中,由于可以确定`number % 10`总是`digitNames`字典的有效下标,因此叹号可以用于强制解包 (force-unwrap) 存储在下标的可选类型的返回值中的`String`类型的值。
-从`digitNames`字典中获取的字符串被添加到`output`的前部,逆序建立了一个字符串版本的数字。(在表达式`number % 10`中,如果`number`为`16`,则返回`6`,`58`返回`8`,`510`返回`0`。)
+从`digitNames`字典中获取的字符串被添加到`output`的*前部*,逆序建立了一个字符串版本的数字。(在表达式`number % 10`中,如果`number`为`16`,则返回`6`,`58`返回`8`,`510`返回`0`。)
`number`变量之后除以`10`。因为其是整数,在计算过程中未除尽部分被忽略。因此`16`变成了`1`,`58`变成了`5`,`510`变成了`51`。
-整个过程重复进行,直到`number /= 10`为`0`,这时闭包会将字符串`output`返回,而`map(_:)`方法则会将字符串添加到所映射的数组中。
+整个过程重复进行,直到`number /= 10`为`0`,这时闭包会将字符串`output`返回,而`map(_:)`方法则会将字符串添加到映射数组中。
在上面的例子中,通过尾随闭包语法,优雅地在函数后封装了闭包的具体功能,而不再需要将整个闭包包裹在`map(_:)`方法的括号内。
-## 捕获值(Capturing Values)
+## 值捕获(Capturing Values)
闭包可以在其被定义的上下文中*捕获*常量或变量。即使定义这些常量和变量的原作用域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。
@@ -256,37 +256,37 @@ Swift 中,可以捕获值的闭包的最简单形式是嵌套函数,也就
举个例子,这有一个叫做`makeIncrementor`的函数,其包含了一个叫做`incrementor`的嵌套函数。嵌套函数`incrementor()`从上下文中捕获了两个值,`runningTotal`和`amount`。捕获这些值之后,`makeIncrementor`将`incrementor`作为闭包返回。每次调用`incrementor`时,其会以`amount`作为增量增加`runningTotal`的值。
```swift
-func makeIncrementor(forIncrement amount: Int) -> () -> Int {
+func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
- func incrementor() -> Int {
+ func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
- return incrementor
+ return incrementer
}
```
-`makeIncrementor`返回类型为`() -> Int`。这意味着其返回的是一个函数,而不是一个简单类型的值。该函数在每次调用时不接受参数,只返回一个`Int`类型的值。关于函数返回其他函数的内容,请查看[函数类型作为返回类型](./06_Functions.html#function_types_as_return_types)。
+`makeIncrementor`返回类型为`() -> Int`。这意味着其返回的是一个*函数*,而非一个简单类型的值。该函数在每次调用时不接受参数,只返回一个`Int`类型的值。关于函数返回其他函数的内容,请查看[函数类型作为返回类型](./06_Functions.html#function_types_as_return_types)。
-`makeIncrementer(forIncrement:)`函数定义了一个初始值为`0`的整型变量`runningTotal`,用来存储当前跑步总数。该值通过`incrementor`返回。
+`makeIncrementer(forIncrement:)`函数定义了一个初始值为`0`的整型变量`runningTotal`,用来存储当前总计数值。该值为`incrementor`的返回值。
`makeIncrementer(forIncrement:)`有一个`Int`类型的参数,其外部参数名为`forIncrement`,内部参数名为`amount`,该参数表示每次`incrementor`被调用时`runningTotal`将要增加的量。
嵌套函数`incrementor`用来执行实际的增加操作。该函数简单地使`runningTotal`增加`amount`,并将其返回。
-如果我们单独看这个函数,会发现看上去不同寻常:
+如果我们单独考虑嵌套函数 `incrementer()`,会发现它有些不同寻常:
```swift
-func incrementor() -> Int {
+func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
```
-`incrementer()`函数并没有任何参数,但是在函数体内访问了`runningTotal`和`amount`变量。这是因为它从外围函数捕获了`runningTotal`和`amount`变量的引用。捕获引用保证了`runningTotal`和`amount`变量在调用完`makeIncrementer`后不会消失,并且保证了在下一次执行`incrementer`函数时,`runningTotal`依旧存在。
+`incrementer()`函数并没有任何参数,但是在函数体内访问了`runningTotal`和`amount`变量。这是因为它从外围函数捕获了`runningTotal`和`amount`变量的*引用*。捕获引用保证了`runningTotal`和`amount`变量在调用完`makeIncrementer`后不会消失,并且保证了在下一次执行`incrementer`函数时,`runningTotal`依旧存在。
> 注意
-> 为了优化,如果一个值是不可变的,Swift 可能会改为捕获并保存一份对值的拷贝。
+> 为了优化,如果一个值不会被闭包改变,或者在闭包创建后不会改变,Swift 可能会改为捕获并保存一份对值的拷贝。
> Swift 也会负责被捕获变量的所有内存管理工作,包括释放不再需要的变量。
下面是一个使用`makeIncrementor`的例子:
@@ -295,7 +295,7 @@ func incrementor() -> Int {
let incrementByTen = makeIncrementor(forIncrement: 10)
```
-该例子定义了一个叫做`incrementByTen`的常量,该常量指向一个每次调用会将`runningTotal`变量增加`10`的`incrementor`函数。调用这个函数多次可以得到以下结果:
+该例子定义了一个叫做`incrementByTen`的常量,该常量指向一个每次调用会将其`runningTotal`变量增加`10`的`incrementor`函数。调用这个函数多次可以得到以下结果:
```swift
incrementByTen()
@@ -306,7 +306,7 @@ incrementByTen()
// 返回的值为30
```
-如果您创建了另一个`incrementor`,它会有属于它自己的一个全新、独立的`runningTotal`变量的引用:
+如果你创建了另一个`incrementor`,它会有属于自己的引用,指向一个全新、独立的`runningTotal`变量:
```swift
let incrementBySeven = makeIncrementor(forIncrement: 7)
@@ -314,7 +314,7 @@ incrementBySeven()
// 返回的值为7
```
-再次调用原来的`incrementByTen`会在原来的变量`runningTotal`上继续增加值,该变量和`incrementBySeven`中捕获的变量没有任何联系:
+再次调用原来的`incrementByTen`会继续增加它自己的`runningTotal`变量,该变量和`incrementBySeven`中捕获的变量没有任何联系:
```swift
incrementByTen()
@@ -322,16 +322,16 @@ incrementByTen()
```
> 注意
-> 如果您将闭包赋值给一个类实例的属性,并且该闭包通过访问该实例或其成员而捕获了该实例,您将创建一个在闭包和该实例间的循环强引用。Swift 使用捕获列表来打破这种循环强引用。更多信息,请参考[闭包引起的循环强引用](./16_Automatic_Reference_Counting.html#strong_reference_cycles_for_closures)。
+> 如果你将闭包赋值给一个类实例的属性,并且该闭包通过访问该实例或其成员而捕获了该实例,你将在闭包和该实例间创建一个循环强引用。Swift 使用捕获列表来打破这种循环强引用。更多信息,请参考[闭包引起的循环强引用](./16_Automatic_Reference_Counting.html#strong_reference_cycles_for_closures)。
## 闭包是引用类型(Closures Are Reference Types)
-上面的例子中,`incrementBySeven`和`incrementByTen`是常量,但是这些常量指向的闭包仍然可以增加其捕获的变量的值。这是因为函数和闭包都是*引用类型*。
+上面的例子中,`incrementBySeven`和`incrementByTen`都是常量,但是这些常量指向的闭包仍然可以增加其捕获的变量的值。这是因为函数和闭包都是*引用类型*。
-无论您将函数或闭包赋值给一个常量还是变量,您实际上都是将常量或变量的值设置为对应函数或闭包的引用。上面的例子中,指向闭包的引用`incrementByTen`是一个常量,而并非闭包内容本身。
+无论你将函数或闭包赋值给一个常量还是变量,你实际上都是将常量或变量的值设置为对应函数或闭包的*引用*。上面的例子中,指向闭包的引用`incrementByTen`是一个常量,而并非闭包内容本身。
-这也意味着如果您将闭包赋值给了两个不同的常量或变量,两个值都会指向同一个闭包:
+这也意味着如果你将闭包赋值给了两个不同的常量或变量,两个值都会指向同一个闭包:
```swift
let alsoIncrementByTen = incrementByTen
@@ -339,73 +339,70 @@ alsoIncrementByTen()
// 返回的值为50
```
-
-## 非逃逸闭包(Nonescaping Closures)
+
+## 逃逸闭包(Escaping Closures)
-当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中*逃逸*。当你定义接受闭包作为参数的函数时,你可以在参数名之前标注`@noescape`,用来指明这个闭包是不允许“逃逸”出这个函数的。将闭包标注`@noescape`能使编译器知道这个闭包的生命周期(译者注:闭包只能在函数体中被执行,不能脱离函数体执行,所以编译器明确知道运行时的上下文),从而可以进行一些比较激进的优化。
-
-```swift
-func someFunctionWithNoescapeClosure(@noescape closure: () -> Void) {
- closure()
-}
-```
-
-举个例子,`sort(_:)`方法接受一个用来进行元素比较的闭包作为参数。这个参数被标注了`@noescape`,因为它确保自己在排序结束之后就没用了。
+当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中*逃逸*。当你定义接受闭包作为参数的函数时,你可以在参数名之前标注`@escaping`,用来指明这个闭包是允许“逃逸”出这个函数的。
一种能使闭包“逃逸”出函数的方法是,将这个闭包保存在一个函数外部定义的变量中。举个例子,很多启动异步操作的函数接受一个闭包参数作为 completion handler。这类函数会在异步操作开始之后立刻返回,但是闭包直到异步操作结束后才会被调用。在这种情况下,闭包需要“逃逸”出函数,因为闭包需要在函数返回之后被调用。例如:
```swift
var completionHandlers: [() -> Void] = []
-func someFunctionWithEscapingClosure(completionHandler: () -> Void) {
+func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
```
-`someFunctionWithEscapingClosure(_:)`函数接受一个闭包作为参数,该闭包被添加到一个函数外定义的数组中。如果你试图将这个参数标注为`@noescape`,你将会获得一个编译错误。
+`someFunctionWithEscapingClosure(_:)`函数接受一个闭包作为参数,该闭包被添加到一个函数外定义的数组中。如果你不将这个参数标记为`@escaping`,你将会获得一个编译错误。
+
+将一个闭包标记为`@escaping`意味着你必须在闭包中显式地引用`self`。比如说,在下面的代码中,传递到 `someFunctionWithEscapingClosure(_:)` 中的闭包是一个逃逸闭包,这意味着它需要显式地引用`self`。相对的,传递到 `someFunctionWithNonescapingClosure(_:)`中的闭包是一个非逃逸闭包,这意味着它可以隐式引用`self`。
-将闭包标注为`@noescape`使你能在闭包中隐式地引用`self`。
```swift
+func someFunctionWithNonescapingClosure(closure: () -> Void) {
+ closure()
+}
+
class SomeClass {
var x = 10
func doSomething() {
someFunctionWithEscapingClosure { self.x = 100 }
- someFunctionWithNoescapeClosure { x = 200 }
+ someFunctionWithNonescapingClosure { x = 200 }
}
}
let instance = SomeClass()
instance.doSomething()
print(instance.x)
-// prints "200"
+// 打印出 "200"
completionHandlers.first?()
print(instance.x)
-// prints "100"
+// 打印出 "100"
```
## 自动闭包(Autoclosures)
-*自动闭包*是一种自动创建的闭包,用于包装传递给函数作为参数的表达式。这种闭包不接受任何参数,当它被调用的时候,会返回被包装在其中的表达式的值。这种便利语法让你能够用一个普通的表达式来代替显式的闭包,从而省略闭包的花括号。
+*自动闭包*是一种自动创建的闭包,用于包装传递给函数作为参数的表达式。这种闭包不接受任何参数,当它被调用的时候,会返回被包装在其中的表达式的值。这种便利语法让你能够省略闭包的花括号,用一个普通的表达式来代替显式的闭包。
-我们经常会调用一个接受闭包作为参数的函数,但是很少实现那样的函数。举个例子来说,`assert(condition:message:file:line:)`函数接受闭包作为它的`condition`参数和`message`参数;它的`condition`参数仅会在 debug 模式下被求值,它的`message`参数仅当`condition`参数为`false`时被计算求值。
+我们经常会*调用*采用自动闭包的函数,但是很少去*实现*这样的函数。举个例子来说,`assert(condition:message:file:line:)`函数接受自动闭包作为它的`condition`参数和`message`参数;它的`condition`参数仅会在 debug 模式下被求值,它的`message`参数仅当`condition`参数为`false`时被计算求值。
-自动闭包让你能够延迟求值,因为代码段不会被执行直到你调用这个闭包。延迟求值对于那些有副作用(Side Effect)和代价昂贵的代码来说是很有益处的,因为你能控制代码什么时候执行。下面的代码展示了闭包如何延时求值。
+自动闭包让你能够延迟求值,因为直到你调用这个闭包,代码段才会被执行。延迟求值对于那些有副作用(Side Effect)和高计算成本的代码来说是很有益处的,因为它使得你能控制代码的执行时机。下面的代码展示了闭包如何延时求值。
```swift
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customersInLine.count)
-// prints "5"
+// 打印出 "5"
-let customerProvider = { customersInLine.removeAtIndex(0) }
+let customerProvider = { customersInLine.remove(at: 0) }
print(customersInLine.count)
-// prints "5"
+// 打印出 "5"
print("Now serving \(customerProvider())!")
-// prints "Now serving Chris!"
+// Prints "Now serving Chris!"
print(customersInLine.count)
-// prints "4"
+// 打印出 "4"
```
尽管在闭包的代码中,`customersInLine`的第一个元素被移除了,不过在闭包被调用之前,这个元素是不会被移除的。如果这个闭包永远不被调用,那么在闭包里面的表达式将永远不会执行,那意味着列表中的元素永远不会被移除。请注意,`customerProvider`的类型不是`String`,而是`() -> String`,一个没有参数且返回值为`String`的函数。
@@ -414,46 +411,46 @@ print(customersInLine.count)
```swift
// customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
-func serveCustomer(customerProvider: () -> String) {
+func serve(customer customerProvider: () -> String) {
print("Now serving \(customerProvider())!")
}
-serveCustomer( { customersInLine.removeAtIndex(0) } )
-// prints "Now serving Alex!"
+serve(customer: { customersInLine.remove(at: 0) } )
+// 打印出 "Now serving Alex!"
```
-`serveCustomer(_:)`接受一个返回顾客名字的显式的闭包。下面这个版本的`serveCustomer(_:)`完成了相同的操作,不过它并没有接受一个显式的闭包,而是通过将参数标记为`@autoclosure`来接收一个自动闭包。现在你可以将该函数当做接受`String`类型参数的函数来调用。`customerProvider`参数将自动转化为一个闭包,因为该参数被标记了`@autoclosure`特性。
+上面的`serve(customer:)`函数接受一个返回顾客名字的显式的闭包。下面这个版本的`serve(customer:)`完成了相同的操作,不过它并没有接受一个显式的闭包,而是通过将参数标记为`@autoclosure`来接收一个自动闭包。现在你可以将该函数当作接受`String`类型参数(而非闭包)的函数来调用。`customerProvider`参数将自动转化为一个闭包,因为该参数被标记了`@autoclosure`特性。
```swift
// customersInLine is ["Ewa", "Barry", "Daniella"]
-func serveCustomer(@autoclosure customerProvider: () -> String) {
+func serve(customer customerProvider: @autoclosure () -> String) {
print("Now serving \(customerProvider())!")
}
-serveCustomer(customersInLine.removeAtIndex(0))
-// prints "Now serving Ewa!"
+serve(customer: customersInLine.remove(at: 0))
+// 打印出 "Now serving Ewa!"
```
> 注意
> 过度使用`autoclosures`会让你的代码变得难以理解。上下文和函数名应该能够清晰地表明求值是被延迟执行的。
-`@autoclosure`特性暗含了`@noescape`特性,这个特性在[非逃逸闭包](#nonescaping_closures)一节中有描述。如果你想让这个闭包可以“逃逸”,则应该使用`@autoclosure(escaping)`特性.
+如果你想让一个自动闭包可以“逃逸”,则应该同时使用`@autoclosure`和`@escaping`属性。`@escaping`属性的讲解见上面的[逃逸闭包](#escaping_closures)
```swift
// customersInLine is ["Barry", "Daniella"]
var customerProviders: [() -> String] = []
-func collectCustomerProviders(@autoclosure(escaping) customerProvider: () -> String) {
+func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> String) {
customerProviders.append(customerProvider)
}
-collectCustomerProviders(customersInLine.removeAtIndex(0))
-collectCustomerProviders(customersInLine.removeAtIndex(0))
+collectCustomerProviders(customersInLine.remove(at: 0))
+collectCustomerProviders(customersInLine.remove(at: 0))
print("Collected \(customerProviders.count) closures.")
-// prints "Collected 2 closures."
+// 打印出 "Collected 2 closures."
for customerProvider in customerProviders {
print("Now serving \(customerProvider())!")
}
-// prints "Now serving Barry!"
-// prints "Now serving Daniella!"
+// 打印出 "Now serving Barry!"
+// 打印出 "Now serving Daniella!"
```
-在上面的代码中,`collectCustomerProviders(_:)`函数并没有调用传入的`customerProvider`闭包,而是将闭包追加到了`customerProviders`数组中。这个数组定义在函数作用域范围外,这意味着数组内的闭包将会在函数返回之后被调用。因此,`customerProvider`参数必须允许“逃逸”出函数作用域。
+在上面的代码中,`collectCustomerProviders(_:)`函数并没有调用传入的`customerProvider`闭包,而是将闭包追加到了`customerProviders`数组中。这个数组定义在函数作用域范围外,这意味着数组内的闭包能够在函数返回之后被调用。因此,`customerProvider`参数必须允许“逃逸”出函数作用域。
From aaf2e886e51011382bc25e2e30eace19e77cadf8 Mon Sep 17 00:00:00 2001
From: chenmingjia <564575471@qq.com>
Date: Sun, 18 Sep 2016 23:42:33 +0800
Subject: [PATCH 06/32] Translate Declarations in Swift 3.0.
Translate Declarations in Swift 3.0.
---
source/chapter3/05_Declarations.md | 32 ++++++++++++++++++++++++++++--
1 file changed, 30 insertions(+), 2 deletions(-)
diff --git a/source/chapter3/05_Declarations.md b/source/chapter3/05_Declarations.md
index 3e8f602a..257b7c96 100755
--- a/source/chapter3/05_Declarations.md
+++ b/source/chapter3/05_Declarations.md
@@ -17,6 +17,9 @@
> 2.2
> 翻译:[星夜暮晨](https://github.com/SemperIdem)
+> 3.0
+> 翻译:[chenmingjia](https://github.com/chenmingjia)
+
本页包含内容:
- [顶级代码](#top-level_code)
@@ -326,6 +329,31 @@ typealias 类型别名 = 现存类型
```
当声明一个类型的别名后,可以在程序的任何地方使用“别名”来代替现有类型。现有类型可以是具有命名的类型或者混合类型。类型别名不产生新的类型,它只是使用别名来引用现有类型。
+类型别名声明可以通过泛型参数来给一个现有泛型类型提供名称。类型别名为现有类型的一部分或者全部泛型参数提供具体类型。例如:
+```swift
+typealias StringDictionary = Dictionary
+
+// 下列两个字典拥有同样的类型
+var dictionary1: StringDictionary = [:]
+var dictionary2: Dictionary = [:]
+```
+当一个类型别名带着泛型参数一起被声明时,这些参数的约束必须与现有参数的约束完全匹配。例如:
+```swift
+typealias DictionaryOfInts = Dictionary
+```
+因为类型别名可以和现有类型相互交换使用,类型别名不可以引入额外的类型约束。
+在协议声明中,类型别名可以为那些经常使用的类型提供一个更短更方便的名称,例如:
+```swift
+protocol Sequence {
+ associatedtype Iterator: IteratorProtocol
+ typealias Element = Iterator.Element
+}
+
+func sum(_ sequence: T) -> Int where T.Element == Int {
+ // ...
+}
+```
+假如没有类型别名,sum函数将必须引用关联类型通过T.Iterator.Element的形式来替代 T.Element。
另请参阅 [协议关联类型声明](#protocol_associated_type_declaration)。
@@ -359,7 +387,7 @@ func 函数名称(参数列表) {
}
```
-每个参数的类型都要标明,因为它们不能被推断出来。虽然函数的参数默认是常量,也可以在参数名前添加 `let` 来强调这一行为。如果您在某个参数名前面加上了 `inout`,那么这个参数就可以在这个函数作用域当中被修改。更多关于 `inout` 参数的讨论,请参阅 [输入输出参数](#in-out_parameters)。
+每个参数的类型都要标明,因为它们不能被推断出来。如果您在某个参数类型前面加上了 `inout`,那么这个参数就可以在这个函数作用域当中被修改。更多关于 `inout` 参数的讨论,请参阅 [输入输出参数](#in-out_parameters)。
函数可以使用元组类型作为返回类型来返回多个值。
@@ -498,7 +526,7 @@ func 函数名称(参数列表) throws -> 返回类型 {
函数或方法可以使用 `rethrows` 关键字来声明,从而表明仅当该函数或方法的一个函数类型的参数抛出错误时,该函数或方法才抛出错误。这类函数和方法被称为重抛函数和重抛方法。重新抛出错误的函数或方法必须至少有一个参数的类型为抛出函数。
```swift
-func functionWithCallback(callback: () throws -> Int) rethrows {
+func someFunction(callback: () throws -> Void) rethrows {
try callback()
}
```
From 0d462b58e0012a87299af92c2b34f0a19e362e21 Mon Sep 17 00:00:00 2001
From: hujiawei
Date: Mon, 19 Sep 2016 22:39:24 +0800
Subject: [PATCH 07/32] Attributes_swift3.0
---
source/chapter3/06_Attributes.md | 213 ++++++++++++++-----------------
1 file changed, 94 insertions(+), 119 deletions(-)
diff --git a/source/chapter3/06_Attributes.md b/source/chapter3/06_Attributes.md
index e1f48024..bf4af714 100755
--- a/source/chapter3/06_Attributes.md
+++ b/source/chapter3/06_Attributes.md
@@ -14,112 +14,113 @@
本页内容包括:
- [声明特性](#declaration_attributes)
- - [Interface Builder 使用的声明特性](#declaration_attributes_used_by_interface_builder)
+- [Interface Builder 使用的声明特性](#declaration_attributes_used_by_interface_builder)
- [类型特性](#type_attributes)
-特性提供了关于声明和类型的更多信息。在 Swift 中有两类特性,分别用于修饰声明和类型。
+特性提供了有关声明和类型的更多信息。在Swift中有两种特性,分别用于修饰声明和类型。
-通过以下方式指定一个特性:符号 `@` 后面跟特性名,如果包含参数,则把参数带上:
+您可以通过以下方式指定一个特性:符号`@`后跟特性的名称和特性接收的任何参数:
-> @`特性名`
-> @`特性名`(`特性参数`)
+> @ `特性名`
+
+> @ `特性名`(`特性参数`)
有些声明特性通过接收参数来指定特性的更多信息以及它是如何修饰某个特定的声明的。这些特性的参数写在圆括号内,它们的格式由它们所属的特性来定义。
-## 声明特性
-
-声明特性只能应用于声明。然而,你也可以将 `noreturn` 特性应用于函数或方法类型。
-
-`autoclosure`
-
-这个特性通过把表达式自动封装成无参数的闭包来延迟表达式的计算。它可以修饰类型为返回表达式结果类型的无参数函数类型的函数参数。含有 `autoclosure` 特性的声明同时也具有 `noescape` 的特性,除非传递可选特性参数 `escaping`。关于如何使用 `autoclosure` 特性的例子,请参阅 [自动闭包](../chapter2/07_Closures.md#autoclosures) 和 [函数类型](03_Types.md#function_type)。
+##声明特性
+声明特性只能应用于声明。
`available`
-将 `available` 特性用于声明时,意味着该声明的生命周期会依赖于特定的平台和操作系统版本。
+将 `available` 特性用于声明时,表示该声明的生命周期与特定的平台和操作系统版本有关。
`available` 特性经常与参数列表一同出现,该参数列表至少有两个特性参数,参数之间由逗号分隔。这些参数由以下这些平台名字中的一个起头:
-- `iOS`
-- `iOSApplicationExtension`
-- `OSX`
-- `OSXApplicationExtension`
-- `watchOS`
-- `watchOSApplicationExtension`
-- `tvOS`
-- `tvOSApplicationExtension`
+- iOS
+- iOSApplicationExtension
+- macOS
+- macOSApplicationExtension
+- watchOS
+- watchOSApplicationExtension
+- tvOS
+- tvOSApplicationExtension
-当然,你也可以用一个星号(`*`)来表示上面提到的所有平台。
-
-剩下的参数,可以以任何顺序出现,并且可以添加关于声明生命周期的附加信息,包括重要事件。
-
-- `unavailable` 参数表示该声明在指定的平台上是无效的。
+当然,你也可以用一个星号(*)来表示上面提到的所有平台。
+其余的参数,可以按照任何顺序出现,并且可以添加关于声明生命周期的附加信息,包括重要事件。
+- `unavailable`参数表示该声明在指定的平台上是无效的。
- `introduced` 参数表示指定平台从哪一版本开始引入该声明。格式如下:
- `introduced`=`版本号`
+`introduced`=`版本号`
-版本号由一个十进制正整数或正浮点数构成。
+*版本号*由一个或多个正整数构成,由句点分隔的。
-- `deprecated` 参数表示指定平台从哪一版本开始弃用该声明。格式如下:
+- `deprecated`参数表示指定平台从哪一版本开始弃用该声明。格式如下:
- `deprecated`=`版本号`
+`deprecated`=`版本号`
-版本号由一个十进制正整数或正浮点数构成。
+可选的*版本号*由一个或多个正整数构成,由句点分隔的。省略版本号表示该声明目前已弃用,当弃用出现时无需给出任何有关信息。如果你省略了版本号,冒号(:)也可省略。
- `obsoleted` 参数表示指定平台从哪一版本开始废弃该声明。当一个声明被废弃后,它就从平台中移除,不能再被使用。格式如下:
- `obsoleted`=`版本号`
+`obsoleted`=`版本号`
-版本号由一个十进制正整数或正浮点数构成。
+*版本号*由一个或多个正整数构成,由句点分隔的。
- `message` 参数用来提供文本信息。当使用被弃用或者被废弃的声明时,编译器会抛出警告或错误信息。格式如下:
- `message`=`信息内容`
+`message`=`信息内容`
-信息内容由一个字符串字面量构成。
+信息内容由一个字符串构成。
- `renamed` 参数用来提供文本信息,用以表示被重命名的声明的新名字。当使用声明的旧名字时,编译器会报错提示新名字。格式如下:
- `renamed`=`新名字`
+`renamed`=`新名字`
-新名字由一个字符串字面量构成。
+新名字由一个字符串构成。
-你可以将 `renamed` 参数和 `unavailable` 参数以及类型别名声明组合使用,以此向用户表示某个声明已经被重命名。当某个声明的名字在一个框架或者库的不同发布版本间发生变化时,这会相当有用。
+你可以将`renamed` 参数和 `unavailable` 参数以及类型别名声明组合使用,以此向用户表示某个声明已经被重命名。当某个声明的名字在一个框架或者库的不同发布版本间发生变化时,这会相当有用。
```swift
// 首发版本
protocol MyProtocol {
- // 这里是协议定义
+// 这里是协议定义
}
```
```swift
// 后续版本重命名了 MyProtocol
protocol MyRenamedProtocol {
- // 这里是协议定义
+// 这里是协议定义
}
-
-@available(*, unavailable, renamed="MyRenamedProtocol")
+@available(*, unavailable, renamed:"MyRenamedProtocol")
typealias MyProtocol = MyRenamedProtocol
```
-你可以在某个声明上使用多个 `available` 特性,以指定该声明在不同平台上的有效性。编译器只有在当前目标平台和 `available` 特性中指定的平台匹配时,才会使用 `available` 特性。
+你可以在某个声明上使用多个 `available` 特性,以指定该声明在不同平台上的可用性。编译器只有在当前目标平台和 `available` 特性中指定的平台匹配时,才会使用 `available` 特性。
如果 `available` 特性除了平台名称参数外,只指定了一个 `introduced` 参数,那么可以使用以下简写语法代替:
-> @available(`平台名称` `版本号`, * )
+@available(平台名称 版本号,*)
`available` 特性的简写语法可以简明地表达出声明在多个平台上的可用性。尽管这两种形式在功能上是相同的,但请尽可能地使用简写语法形式。
```swift
-@available(iOS 8.0, OSX 10.10, *)
+@available(iOS 10.0, macOS 10.12, *)
class MyClass {
- // 这里是类定义
+// 这里是类定义
}
```
+`discardableResult`
+
+该特性用于的函数或方法声明,以抑制编译器中 函数或方法的返回值被调而没有使用其结果的警告。
+
+`GKInspectable`
+
+应用此属性,暴露一个自定义GameplayKit组件属性给SpriteKit编辑器UI。
+
`objc`
该特性用于修饰任何可以在 Objective-C 中表示的声明。比如,非嵌套类、协议、非泛型枚举(仅限原始值为整型的枚举)、类和协议中的属性和方法(包括存取方法)、构造器、析构器以及下标运算符。`objc` 特性告诉编译器这个声明可以在 Objective-C 代码中使用。
@@ -128,23 +129,17 @@ class MyClass {
如果你将 `objc` 特性应用于枚举,每一个枚举用例都会以枚举名称和用例名称组合的方式暴露在 Objective-C 代码中。例如,在 `Planet` 枚举中有一个名为 `Venus` 的用例,该用例暴露在 Objective-C 代码中时叫做 `PlanetVenus`。
-`objc` 特性有一个可选的参数,由标识符构成。当你想把 `objc` 所修饰的实体以一个不同的名字暴露给 Objective-C 时,你就可以使用这个特性参数。你可以使用这个参数来命名类、枚举类型、枚举用例、协议、方法、存取方法以及构造器。下面的例子把 `ExampleClass` 中的 `enabled` 属性的取值方法暴露给 Objective-C,名字是 `isEnabled`,而不是它原来的属性名。
+`objc` 特性有一个可选的参数,由标识符构成。当你想把 objc 所修饰的实体以一个不同的名字暴露给 Objective-C 时,你就可以使用这个特性参数。你可以使用这个参数来命名类、枚举类型、枚举用例、协议、方法、存取方法以及构造器。下面的例子把 `ExampleClass` 中的 `enabled` 属性的取值方法暴露给 Objective-C,名字是 `isEnabled`,而不是它原来的属性名。
```swift
@objc
class ExampleClass: NSObject {
- var enabled: Bool {
- @objc(isEnabled) get {
- // 返回适当的值
- }
- }
+var enabled: Bool {
+@objc(isEnabled) get {
+// 返回适当的值 }
+}
}
```
-
-`noescape`
-
-在函数或者方法声明上使用该特性,它表示参数将不会被存储以供延迟执行,这将确保参数不会超出函数调用的生命周期。在使用 `noescape` 声明特性的函数类型中访问属性和方法时不需要显式地使用 `self.`。关于如何使用 `noescape` 特性的例子,请参阅 [非逃逸闭包](../chapter2/07_Closures.md#nonescaping_closures)。
-
`nonobjc`
该特性用于方法、属性、下标、或构造器的声明,这些声明本可以在 Objective-C 代码中使用,而使用 `nonobjc` 特性则告诉编译器这个声明不能在 Objective-C 代码中使用。
@@ -153,77 +148,56 @@ class ExampleClass: NSObject {
标有 `nonobjc` 特性的方法不能重写标有 `objc` 特性的方法。然而,标有 `objc` 特性的方法可以重写标有 `nonobjc` 特性的方法。同样,标有 `nonobjc` 特性的方法不能满足标有 `@objc` 特性的协议中的方法要求。
-`noreturn`
-
-该特性用于修饰函数或方法声明,表明该函数或方法的对应类型 `T` 是 `@noreturn T`。你可以用这个特性修饰函数或方法类型,以此表明函数或方法不会返回到它的调用者。
-
-对于没有用 `noreturn` 特性标记的函数或方法,你可以将它重写为用该特性标记的。相反,对于已经用 `noreturn` 特性标记的函数或方法,你不可以将它重写为没使用该特性标记的。当你在一个某个采纳协议的类型中实现协议方法时,该规则同样适用。
-
`NSApplicationMain`
-在类上使用该特性表示该类是应用程序委托类,使用该特性与调用 `NSApplicationMain(_:_:)` 函数并且把该类的名字作为委托类的名字传递给函数的效果相同。
+在类上使用该特性表示该类是应用程序委托类,使用该特性与调用 `NSApplicationMain`(\_:_:) 函数并且把该类的名字作为委托类的名字传递给函数的效果相同。
-如果你不想使用这个特性,可以提供一个 `main.swift` 文件,并且提供一个 `main()` 函数去调用 `NSApplicationMain(_:_:)` 函数。比如,如果你的应用程序使用一个继承于 `NSApplication` 的自定义子类作为主要类,你可以调用 `NSApplicationMain(_:_:)` 函数而不是使用该特性。
+如果你不想使用这个特性,可以提供一个 main.swift 文件,并在代码**顶层**调用`NSApplicationMain`(\_:_:) 函数,如下所示:
+```swift
+import AppKit
+NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
+```
`NSCopying`
-该特性用于修饰一个类的存储型变量属性。该特性将使属性的设值方法使用传入值的副本进行赋值,这个值由传入值的 `copyWithZone(_:)` 方法返回。该属性的类型必需符合 `NSCopying` 协议。
+该特性用于修饰一个类的存储型变量属性。该特性将使属性的设值方法使用传入值的副本进行赋值,这个值由传入值的 `copyWithZone`(\_:) 方法返回。该属性的类型必需符合 `NSCopying` 协议。
`NSCopying` 特性的行为与 Objective-C 中的 `copy` 特性相似。
`NSManaged`
-该特性用于修饰 `NSManagedObject` 子类中的实例方法或存储型变量属性,表明它们的实现由 Core Data 在运行时基于相关实体描述动态提供。对于标记了 `NSManaged` 特性的属性,Core Data 也会在运行时为其提供存储。
+该特性用于修饰 `NSManagedObject` 子类中的实例方法或存储型变量属性,表明它们的实现由 `Core Data` 在运行时基于相关实体描述动态提供。对于标记了 `NSManaged` 特性的属性,`Core Data` 也会在运行时为其提供存储。应用这个特性也意味着`objc`特性。
`testable`
-在导入允许测试的编译模块时,该特性用于修饰 `import` 声明,这样就能访问被导入模块中的任何标有 `internal` 访问级别修饰符的实体,犹如它们被标记了 `public` 访问级别修饰符。
+在导入允许测试的编译模块时,该特性用于修饰 `import` 声明,这样就能访问被导入模块中的任何标有 `internal` 访问级别修饰符的实体,犹如它们被标记了 `public` 访问级别修饰符。测试也可以访问使用`internal`或者`public`访问级别修饰符标记的类和类成员,就像它们是`open`访问修饰符声明的。
`UIApplicationMain`
-在类上使用该特性表示该类是应用程序委托类,使用该特性与调用 `UIApplicationMain(_:_:)` 函数并且把该类的名字作为委托类的名字传递给函数的效果相同。
+在类上使用该特性表示该类是应用程序委托类,使用该特性与调用 `UIApplicationMain`函数并且把该类的名字作为委托类的名字传递给函数的效果相同。
-如果你不想使用这个特性,可以提供一个 `main.swift` 文件,并且提供一个 `main()` 函数去调用 `UIApplicationMain(_:_:)` 函数。比如,如果你的应用程序使用一个继承于 `UIApplication` 的自定义子类作为主要类,你可以调用 `UIApplicationMain(_:_:_:)` 函数而不是使用该特性。
-
-`warn_unused_result`
-
-该特性应用于方法或函数声明,当方法或函数被调用,但其结果未被使用时,该特性会让编译器会产生警告。
-
-当某个方法有一个对应的变异版本,但是用户却还是错误地使用了非变异版本时,你可以使用这个特性提供一个警告信息。
-
-`warn_unused_result` 特性可以选择接受下面两个参数之中的一个。
-
-- `message` 参数用来提供警告信息。当方法或函数被调用,但其结果未被使用时,会显示警告信息。格式如下:
-
- `message`=`警告信息`
-
-警告信息由一个字符串字面量构成。
-
-- `mutable_variant` 参数用于提供方法的变异版本的名称,如果非变异方法在一个可变值上调用,但是返回结果却未被使用时,应该使用此方法的变异版本。格式如下:
-
- `mutable_variant`=`变异版本的方法名`
-
-变异版本的方法名由一个字符串字面量构成。
-
-比如,Swift 标准库同时为元素符合 `Comparable` 协议的集合类型提供了变异方法 `sortInPlace()` 和非变异方法 `sort()`。如果你调用了 `sort()` 方法,却没有使用它的返回结果,那么你很可能本想使用变异方法 `sortInPlace()`。
+如果你不想使用这个特性,可以提供一个 main.swift 文件,并在代码顶层调用 `UIApplicationMain`(\_:\_:\_:) 函数。比如,如果你的应用程序使用一个继承于 UIApplication 的自定义子类作为主要类,你可以调用 `UIApplicationMain`(\_:\_:\_:) 函数而不是使用该特性。
-### Interface Builder 使用的声明特性
-
-Interface Builder 特性是 Interface Builder 用来与 Xcode 同步的声明特性。Swift 提供了以下的 Interface Builder 特性:`IBAction`,`IBDesignable`,`IBInspectable`,以及 `IBOutlet`。这些特性与 Objective-C 中对应的特性在概念上是相同的。
+###Interface Builder 使用的声明特性
+`Interface Builder` 特性是 `Interface Builder` 用来与 Xcode 同步的声明特性。`Swift` 提供了以下的 `Interface Builder` 特性:`IBAction`,`IBOutlet`,`IBDesignable`,以及`IBInspectable` 。这些特性与 Objective-C 中对应的特性在概念上是相同的。
`IBOutlet` 和 `IBInspectable` 用于修饰一个类的属性声明,`IBAction` 特性用于修饰一个类的方法声明,`IBDesignable` 用于修饰类的声明。
-
-## 类型特性
+`IBAction` 和 `IBOutlet` 特性都意味着`objc`特性。
-类型特性只能用于修饰类型。然而,你也可以用 `noreturn` 特性去修饰函数或方法声明。
+
+##类型特性
+类型特性只能用于修饰类型。
+
+`autoclosure`
+
+这个特性通过把表达式自动封装成无参数的闭包来延迟表达式的计算。它可以修饰类型为返回表达式结果类型的无参数函数类型的函数参数。关于如何使用 autoclosure 特性的例子,请参阅 [自动闭包](http://wiki.jikexueyuan.com/project/swift/chapter2/07_Closures.html/) 和 [函数类型](http://wiki.jikexueyuan.com/project/swift/chapter3/03_Types.html)。
`convention`
-
该特性用于修饰函数类型,它指出了函数调用的约定。
-`convention` 特性总是与下面的参数之一一起出现。
+convention 特性总是与下面的参数之一一起出现。
- `swift` 参数用于表示一个 Swift 函数引用。这是 Swift 中函数值的标准调用约定。
@@ -233,26 +207,27 @@ Interface Builder 特性是 Interface Builder 用来与 Xcode 同步的声明特
使用 C 函数调用约定的函数也可用作使用 Objective-C 块调用约定的函数,同时使用 Objective-C 块调用约定的函数也可用作使用 Swift 函数调用约定的函数。然而,只有非泛型的全局函数、局部函数以及未捕获任何局部变量的闭包,才可以被用作使用 C 函数调用约定的函数。
-`noreturn`
+`escaping`
+在函数或者方法声明上使用该特性,它表示参数将不会被存储以供延迟执行,这将确保参数不会超出函数调用的生命周期。在使用 `escaping` 声明特性的函数类型中访问属性和方法时不需要显式地使用 `self.`。关于如何使用 `escaping` 特性的例子,请参阅 [逃逸闭包](http://wiki.jikexueyuan.com/project/swift/chapter2/07_Closures.html)。
-该特性用于修饰函数或方法的类型,表明该函数或方法不会返回到它的调用者。你也可以用它标记函数或方法的声明,表示函数或方法的相应类型 `T` 是 `@noreturn T`。
+>特性语法
-> 特性语法
+> *特性 *→ @ 特性名 特性参数子句可选
-
-> *特性* → **@** [*特性名*](#attribute-name) [*特性参数子句*](#attribute-argument-clause)可选
-
-> *特性名* → [*标识符*](02_Lexical_Structure.md#identifiers)
-
-> *特性参数子句* → **(** [*均衡令牌列表*](#balanced-tokens)可选 **)**
-
-> *特性列表* → [*特性*](#attribute) [*特性列表*](#attributes)可选
+> *特性名* → 标识符
-
-> *均衡令牌列表* → [*均衡令牌*](#balanced-token) [*均衡令牌列表*](#balanced-tokens)可选
-
-> *均衡令牌* → **(** [*均衡令牌列表*](#balanced-tokens)可选 **)**
-> *均衡令牌* → **[** [*均衡令牌列表*](#balanced-tokens)可选 **]**
-> *均衡令牌* → **{** [*均衡令牌列表*](#balanced-tokens)可选 **}**
-> *均衡令牌* → **任意标识符,关键字,字面量或运算符**
-> *均衡令牌* → **任意标点除了 (,),[,],{,或 }**
+> *特性参数子句* → ( 均衡令牌列表可选 )
+
+> *特性列表* → 特性 特性列表可选
+
+> *均衡令牌列表* → 均衡令牌 均衡令牌列表可选
+
+> *均衡令牌* → ( 均衡令牌列表可选 )
+
+> *均衡令牌* → [ 均衡令牌列表可选 ]
+
+> *均衡令牌* → { 均衡令牌列表可选}
+
+> *均衡令牌* → 任意标识符,关键字,字面量或运算符
+
+> *均衡令牌* → 任意标点除了 (,),[,],{,或 }
From ed9a67ba9dfaaf4b6313a0c9278794d0a9da2777 Mon Sep 17 00:00:00 2001
From: Cai Linfeng
Date: Mon, 19 Sep 2016 23:33:16 +0800
Subject: [PATCH 08/32] update chapter 'Closure' to swift 3.0
---
source/chapter2/07_Closures.md | 150 ++++++++++++++++-----------------
1 file changed, 75 insertions(+), 75 deletions(-)
diff --git a/source/chapter2/07_Closures.md b/source/chapter2/07_Closures.md
index c2b6c9db..3fc7d74f 100755
--- a/source/chapter2/07_Closures.md
+++ b/source/chapter2/07_Closures.md
@@ -14,6 +14,9 @@
>
> 2.2
> 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-12
+>
+> 3.0
+> 翻译:[Lanford](https://github.com/LanfordCai) 2016-09-19
本页包含内容:
@@ -28,7 +31,7 @@
闭包可以捕获和存储其所在上下文中任意常量和变量的引用。*闭合、包裹*常量和变量,所谓闭包也。Swift 会为你管理在捕获过程中涉及到的所有内存操作。
-> 注意
+> 注意
> 如果你不熟悉捕获(capturing)这个概念也不用担心,你可以在[值捕获](#capturing_values)章节对其进行详细了解。
在[函数](./06_Functions.html)章节中介绍的全局和嵌套函数实际上也是特殊的闭包,闭包采取如下三种形式之一:
@@ -40,7 +43,7 @@
Swift 的闭包表达式拥有简洁的风格,并鼓励在常见场景中进行语法优化,主要优化如下:
* 利用上下文推断参数和返回值类型
-* 隐式返回单表达式闭包,即单表达式闭包可以省略`return`关键字
+* 隐式返回单表达式闭包,即单表达式闭包可以省略 `return` 关键字
* 参数名称缩写
* 尾随(Trailing)闭包语法
@@ -50,24 +53,24 @@ Swift 的闭包表达式拥有简洁的风格,并鼓励在常见场景中进
[嵌套函数](./06_Functions.html#nested_function)是一个在较复杂函数中方便进行命名和定义自包含代码模块的方式。当然,有时候编写小巧的没有完整定义和命名的类函数结构也是很有用处的,尤其是在你处理一些函数并需要将另外一些函数作为该函数的参数时。
-*闭包表达式*是一种利用简洁语法构建内联闭包的方式。闭包表达式提供了一些语法优化,使得撰写闭包变得简单明了。下面闭包表达式的例子通过使用几次迭代展示了`sorted(by:)`方法定义和语法优化的方式。每一次迭代都用更简洁的方式描述了相同的功能。
+*闭包表达式*是一种利用简洁语法构建内联闭包的方式。闭包表达式提供了一些语法优化,使得撰写闭包变得简单明了。下面闭包表达式的例子通过使用几次迭代展示了 `sorted(by:)` 方法定义和语法优化的方式。每一次迭代都用更简洁的方式描述了相同的功能。
### sorted 方法(The Sorted Method)
-Swift 标准库提供了名为`sorted(by:)`的方法,会根据你所提供的用于排序的闭包函数将已知类型数组中的值进行排序。一旦排序完成,`sorted(by:)`方法会返回一个与原数组大小相同,包含同类型元素且元素已正确排序的新数组。原数组不会被`sorted(by:)`方法修改。
+Swift 标准库提供了名为 `sorted(by:)` 的方法,它会根据你所提供的用于排序的闭包函数将已知类型数组中的值进行排序。一旦排序完成,`sorted(by:)` 方法会返回一个与原数组大小相同,包含同类型元素且元素已正确排序的新数组。原数组不会被 `sorted(by:)` 方法修改。
-下面的闭包表达式示例使用`sorted(by:)`方法对一个`String`类型的数组进行字母逆序排序.以下是初始数组值:
+下面的闭包表达式示例使用 `sorted(by:)` 方法对一个 `String` 类型的数组进行字母逆序排序。以下是初始数组:
```swift
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
```
-`sorted(by:)`方法接受一个闭包,该闭包函数需要传入与数组元素类型相同的两个值,并返回一个布尔类型值来表明当排序结束后传入的第一个参数排在第二个参数前面还是后面。如果第一个参数值出现在第二个参数值*前面*,排序闭包函数需要返回`true`,反之返回`false`。
+`sorted(by:)` 方法接受一个闭包,该闭包函数需要传入与数组元素类型相同的两个值,并返回一个布尔类型值来表明当排序结束后传入的第一个参数排在第二个参数前面还是后面。如果第一个参数值出现在第二个参数值*前面*,排序闭包函数需要返回`true`,反之返回`false`。
-该例子对一个`String`类型的数组进行排序,因此排序闭包函数类型需为`(String, String) -> Bool`。
+该例子对一个 `String` 类型的数组进行排序,因此排序闭包函数类型需为 `(String, String) -> Bool`。
-提供排序闭包函数的一种方式是撰写一个符合其类型要求的普通函数,并将其作为`sorted(by:)`方法的参数传入:
+提供排序闭包函数的一种方式是撰写一个符合其类型要求的普通函数,并将其作为 `sorted(by:)` 方法的参数传入:
```swift
func backward(_ s1: String, _ s2: String) -> Bool {
@@ -77,7 +80,7 @@ var reversedNames = names.sorted(by: backward)
// reversedNames 为 ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
```
-如果第一个字符串(`s1`)大于第二个字符串(`s2`),`backward(_:_:)`函数会返回`true`,表示在新的数组中`s1`应该出现在`s2`前。对于字符串中的字符来说,“大于”表示“按照字母顺序较晚出现”。这意味着字母`"B"`大于字母`"A"`,字符串`"Tom"`大于字符串`"Tim"`。该闭包将进行字母逆序排序,`"Barry"`将会排在`"Alex"`之前。
+如果第一个字符串(`s1`)大于第二个字符串(`s2`),`backward(_:_:)` 函数会返回 `true`,表示在新的数组中 `s1` 应该出现在 `s2` 前。对于字符串中的字符来说,“大于”表示“按照字母顺序较晚出现”。这意味着字母 `"B"` 大于字母 `"A"` ,字符串 `"Tom"` 大于字符串 `"Tim"`。该闭包将进行字母逆序排序,`"Barry"` 将会排在 `"Alex"` 之前。
然而,以这种方式来编写一个实际上很简单的表达式(`a > b`),确实太过繁琐了。对于这个例子来说,利用闭包表达式语法可以更好地构造一个内联排序闭包。
@@ -92,10 +95,9 @@ var reversedNames = names.sorted(by: backward)
}
```
-// MARK:
-闭包表达式的参数可以使inout参数,但不能设定默认值。也可以使用具名的可变参数。元组也可以作为参数和返回值。
+闭包表达式的参数可以是inout参数,但不能设定默认值。也可以使用具名的可变参数(译者注:但是如果可变参数不放在参数列表的最后一位的话,调用闭包的时时编译器将报错。可参考[这里](http://stackoverflow.com/questions/39548852/swift-3-0-closure-expression-what-if-the-variadic-parameters-not-at-the-last-pl))。元组也可以作为参数和返回值。
-下面的例子展示了之前`backward(_:_:)`函数对应的闭包表达式版本的代码:
+下面的例子展示了之前 `backward(_:_:)` 函数对应的闭包表达式版本的代码:
```swift
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
@@ -103,7 +105,7 @@ reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
})
```
-需要注意的是内联闭包参数和返回值类型声明与`backward(_:_:)`函数类型声明相同。在这两种方式中,都写成了`(s1: String, s2: String) -> Bool`。然而在内联闭包表达式中,函数和返回值类型都写在*大括号内*,而不是大括号外。
+需要注意的是内联闭包参数和返回值类型声明与 `backward(_:_:)` 函数类型声明相同。在这两种方式中,都写成了 `(s1: String, s2: String) -> Bool`。然而在内联闭包表达式中,函数和返回值类型都写在*大括号内*,而不是大括号外。
闭包的函数体部分由关键字`in`引入。该关键字表示闭包的参数和返回值类型定义已经完成,闭包函数体即将开始。
@@ -113,12 +115,12 @@ reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } )
```
-该例中`sorted(by:)`方法的整体调用保持不变,一对圆括号仍然包裹住了方法的整个参数。然而,参数现在变成了内联闭包。
+该例中 `sorted(by:)` 方法的整体调用保持不变,一对圆括号仍然包裹住了方法的整个参数。然而,参数现在变成了内联闭包。
### 根据上下文推断类型(Inferring Type From Context)
-因为排序闭包函数是作为`sorted(by:)`方法的参数传入的,Swift 可以推断其参数和返回值的类型。`sorted(by:)`方法被一个字符串数组调用,因此其参数必须是`(String, String) -> Bool`类型的函数。这意味着`(String, String)`和`Bool`类型并不需要作为闭包表达式定义的一部分。因为所有的类型都可以被正确推断,返回箭头(`->`)和围绕在参数周围的括号也可以被省略:
+因为排序闭包函数是作为 `sorted(by:)` 方法的参数传入的,Swift 可以推断其参数和返回值的类型。`sorted(by:)` 方法被一个字符串数组调用,因此其参数必须是 `(String, String) -> Bool` 类型的函数。这意味着 `(String, String)` 和 `Bool` 类型并不需要作为闭包表达式定义的一部分。因为所有的类型都可以被正确推断,返回箭头(`->`)和围绕在参数周围的括号也可以被省略:
```swift
reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )
@@ -126,23 +128,23 @@ reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )
实际上,通过内联闭包表达式构造的闭包作为参数传递给函数或方法时,总是能够推断出闭包的参数和返回值类型。这意味着闭包作为函数或者方法的参数时,你几乎不需要利用完整格式构造内联闭包。
-尽管如此,你仍然可以明确写出有着完整格式的闭包。如果完整格式的闭包能够提高代码的可读性,则我们更鼓励采用完整格式的闭包。而在`sorted(by:)`方法这个例子里,显然闭包的目的就是排序。由于这个闭包是为了处理字符串数组的排序,因此读者能够推测出这个闭包是用于字符串处理的。
+尽管如此,你仍然可以明确写出有着完整格式的闭包。如果完整格式的闭包能够提高代码的可读性,则我们更鼓励采用完整格式的闭包。而在 `sorted(by:)` 方法这个例子里,显然闭包的目的就是排序。由于这个闭包是为了处理字符串数组的排序,因此读者能够推测出这个闭包是用于字符串处理的。
-### 单表达式闭包隐式返回(Implicit Return From Single-Expression Clossures)
+### 单表达式闭包隐式返回(Implicit Returns From Single-Expression Closures)
-单行表达式闭包可以通过省略`return`关键字来隐式返回单行表达式的结果,如上版本的例子可以改写为:
+单行表达式闭包可以通过省略 `return` 关键字来隐式返回单行表达式的结果,如上版本的例子可以改写为:
```swift
reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
```
-在这个例子中,`sorted(by:)`方法的参数类型明确了闭包必须返回一个`Bool`类型值。因为闭包函数体只包含了一个单一表达式(`s1 > s2`),该表达式返回`Bool`类型值,因此这里没有歧义,`return`关键字可以省略。
+在这个例子中,`sorted(by:)` 方法的参数类型明确了闭包必须返回一个 `Bool` 类型值。因为闭包函数体只包含了一个单一表达式(`s1 > s2`),该表达式返回 `Bool` 类型值,因此这里没有歧义,`return` 关键字可以省略。
### 参数名称缩写(Shorthand Argument Names)
-Swift 自动为内联闭包提供了参数名称缩写功能,你可以直接通过`$0`,`$1`,`$2`来顺序调用闭包的参数,以此类推。
+Swift 自动为内联闭包提供了参数名称缩写功能,你可以直接通过 `$0`,`$1`,`$2` 来顺序调用闭包的参数,以此类推。
如果你在闭包表达式中使用参数名称缩写,你可以在闭包定义中省略参数列表,并且对应参数名称缩写的类型会通过函数类型进行推断。`in`关键字也同样可以被省略,因为此时闭包表达式完全由闭包函数体构成:
@@ -150,23 +152,23 @@ Swift 自动为内联闭包提供了参数名称缩写功能,你可以直接
reversedNames = names.sorted(by: { $0 > $1 } )
```
-在这个例子中,`$0`和`$1`表示闭包中第一个和第二个`String`类型的参数。
+在这个例子中,`$0`和`$1`表示闭包中第一个和第二个 `String` 类型的参数。
-
-### 运算符函数(Operator Functions)
+
+### 运算符方法(Operator Methods)
-实际上还有一种更简短的方式来编写上面例子中的闭包表达式。Swift 的`String`类型定义了关于大于号(`>`)的字符串实现,其作为一个函数接受两个`String`类型的参数并返回`Bool`类型的值。而这正好与`sorted(by:)`方法的参数需要的函数类型相符合。因此,你可以简单地传递一个大于号,Swift 可以自动推断出你想使用大于号的字符串函数实现:
+实际上还有一种更简短的方式来编写上面例子中的闭包表达式。Swift 的 `String` 类型定义了关于大于号(`>`)的字符串实现,其作为一个函数接受两个 `String` 类型的参数并返回 `Bool` 类型的值。而这正好与 `sorted(by:)` 方法的参数需要的函数类型相符合。因此,你可以简单地传递一个大于号,Swift 可以自动推断出你想使用大于号的字符串函数实现:
```swift
reversedNames = names.sorted(by: >)
```
-更多关于运算符表达式的内容请查看[运算符函数](./25_Advanced_Operators.html#operator_functions)。
+更多关于运算符方法的内容请查看[运算符方法](./25_Advanced_Operators.html#operator_methods)。
## 尾随闭包(Trailing Closures)
-如果你需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用*尾随闭包*来增强函数的可读性。尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用:
+如果你需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用*尾随闭包*来增强函数的可读性。尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。在使用尾随闭包时,你不用写出它的参数标签:
```swift
func someFunctionThatTakesAClosure(closure: () -> Void) {
@@ -184,23 +186,23 @@ someFunctionThatTakesAClosure() {
}
```
-在[闭包表达式语法](#closure_expression_syntax)一节中作为`sorted(by:)`方法参数的字符串排序闭包可以改写为:
+在[闭包表达式语法](#closure_expression_syntax)一节中作为 `sorted(by:)` 方法参数的字符串排序闭包可以改写为:
```swift
reversedNames = names.sorted() { $0 > $1 }
```
-如果闭包表达式是函数或方法的唯一参数,则当你使用尾随闭包时,你甚至可以把`()`省略掉:
+如果闭包表达式是函数或方法的唯一参数,则当你使用尾随闭包时,你甚至可以把 `()` 省略掉:
```swift
reversedNames = names.sorted { $0 > $1 }
```
-当闭包非常长以至于不能在一行中进行书写时,尾随闭包变得非常有用。举例来说,Swift 的`Array`类型有一个`map(_:)`方法,这个方法获取一个闭包表达式作为其唯一参数。该闭包函数会为数组中的每一个元素调用一次,并返回该元素所映射的值。具体的映射方式和返回值类型由闭包来指定。
+当闭包非常长以至于不能在一行中进行书写时,尾随闭包变得非常有用。举例来说,Swift 的 `Array` 类型有一个 `map(_:)` 方法,这个方法获取一个闭包表达式作为其唯一参数。该闭包函数会为数组中的每一个元素调用一次,并返回该元素所映射的值。具体的映射方式和返回值类型由闭包来指定。
-当提供给数组的闭包应用于每个数组元素后,`map(_:)`方法将返回一个新的数组,数组中包含了与原数组中的元素一一对应的映射后的值。
+当提供给数组的闭包应用于每个数组元素后,`map(_:)` 方法将返回一个新的数组,数组中包含了与原数组中的元素一一对应的映射后的值。
-下例介绍了如何在`map(_:)`方法中使用尾随闭包将`Int`类型数组`[16, 58, 510]`转换为包含对应`String`类型的值的数组`["OneSix", "FiveEight", "FiveOneZero"]`:
+下例介绍了如何在 `map(_:)` 方法中使用尾随闭包将 `Int` 类型数组 `[16, 58, 510]` 转换为包含对应 `String` 类型的值的数组`["OneSix", "FiveEight", "FiveOneZero"]`:
```swift
let digitNames = [
@@ -212,7 +214,7 @@ let numbers = [16, 58, 510]
如上代码创建了一个整型数位和它们英文版本名字相映射的字典。同时还定义了一个准备转换为字符串数组的整型数组。
-你现在可以通过传递一个尾随闭包给`numbers`的`map(_:)`方法来创建对应的字符串版本数组:
+你现在可以通过传递一个尾随闭包给 `numbers` 数组的 `map(_:)` 方法来创建对应的字符串版本数组:
```swift
let strings = numbers.map {
@@ -229,22 +231,22 @@ let strings = numbers.map {
// 其值为 ["OneSix", "FiveEight", "FiveOneZero"]
```
-`map(_:)`为数组中每一个元素调用了一次闭包表达式。你不需要指定闭包的输入参数`number`的类型,因为可以通过要映射的数组类型进行推断。
+`map(_:)` 为数组中每一个元素调用了一次闭包表达式。你不需要指定闭包的输入参数 `number` 的类型,因为可以通过要映射的数组类型进行推断。
-在该例中,局部变量`number`的值由闭包中的`number`参数获得,因此可以在闭包函数体内对其进行修改,(闭包或者函数的参数总是常量),闭包表达式指定了返回类型为`String`,以表明存储映射值的新数组类型为`String`。
+在该例中,局部变量 `number` 的值由闭包中的 `number` 参数获得,因此可以在闭包函数体内对其进行修改,(闭包或者函数的参数总是常量),闭包表达式指定了返回类型为 `String`,以表明存储映射值的新数组类型为 `String`。
-闭包表达式在每次被调用的时候创建了一个叫做`output`的字符串并返回。其使用求余运算符(`number % 10`)计算最后一位数字并利用`digitNames`字典获取所映射的字符串。这个闭包能够用于创建任意正整数的字符串表示。
+闭包表达式在每次被调用的时候创建了一个叫做 `output` 的字符串并返回。其使用求余运算符(`number % 10`)计算最后一位数字并利用 `digitNames` 字典获取所映射的字符串。这个闭包能够用于创建任意正整数的字符串表示。
-> 注意
-> 字典`digitNames`下标后跟着一个叹号(`!`),因为字典下标返回一个可选值(optional value),表明该键不存在时会查找失败。在上例中,由于可以确定`number % 10`总是`digitNames`字典的有效下标,因此叹号可以用于强制解包 (force-unwrap) 存储在下标的可选类型的返回值中的`String`类型的值。
+> 注意
+> 字典 `digitNames` 下标后跟着一个叹号(`!`),因为字典下标返回一个可选值(optional value),表明该键不存在时会查找失败。在上例中,由于可以确定 `number % 10` 总是 `digitNames` 字典的有效下标,因此叹号可以用于强制解包 (force-unwrap) 存储在下标的可选类型的返回值中的`String`类型的值。
-从`digitNames`字典中获取的字符串被添加到`output`的*前部*,逆序建立了一个字符串版本的数字。(在表达式`number % 10`中,如果`number`为`16`,则返回`6`,`58`返回`8`,`510`返回`0`。)
+从 `digitNames` 字典中获取的字符串被添加到 `output` 的*前部*,逆序建立了一个字符串版本的数字。(在表达式 `number % 10` 中,如果 `number` 为 `16`,则返回 `6`,`58` 返回 `8`,`510` 返回 `0`。)
-`number`变量之后除以`10`。因为其是整数,在计算过程中未除尽部分被忽略。因此`16`变成了`1`,`58`变成了`5`,`510`变成了`51`。
+`number` 变量之后除以 `10`。因为其是整数,在计算过程中未除尽部分被忽略。因此 `16` 变成了 `1`,`58` 变成了 `5`,`510` 变成了 `51`。
-整个过程重复进行,直到`number /= 10`为`0`,这时闭包会将字符串`output`返回,而`map(_:)`方法则会将字符串添加到映射数组中。
+整个过程重复进行,直到 `number /= 10` 为 `0`,这时闭包会将字符串 `output` 返回,而 `map(_:)` 方法则会将字符串添加到映射数组中。
-在上面的例子中,通过尾随闭包语法,优雅地在函数后封装了闭包的具体功能,而不再需要将整个闭包包裹在`map(_:)`方法的括号内。
+在上面的例子中,通过尾随闭包语法,优雅地在函数后封装了闭包的具体功能,而不再需要将整个闭包包裹在 `map(_:)` 方法的括号内。
## 值捕获(Capturing Values)
@@ -253,7 +255,7 @@ let strings = numbers.map {
Swift 中,可以捕获值的闭包的最简单形式是嵌套函数,也就是定义在其他函数的函数体内的函数。嵌套函数可以捕获其外部函数所有的参数以及定义的常量和变量。
-举个例子,这有一个叫做`makeIncrementor`的函数,其包含了一个叫做`incrementor`的嵌套函数。嵌套函数`incrementor()`从上下文中捕获了两个值,`runningTotal`和`amount`。捕获这些值之后,`makeIncrementor`将`incrementor`作为闭包返回。每次调用`incrementor`时,其会以`amount`作为增量增加`runningTotal`的值。
+举个例子,这有一个叫做 `makeIncrementor` 的函数,其包含了一个叫做 `incrementor` 的嵌套函数。嵌套函数 `incrementor()` 从上下文中捕获了两个值,`runningTotal` 和 `amount`。捕获这些值之后,`makeIncrementor` 将 `incrementor` 作为闭包返回。每次调用 `incrementor` 时,其会以 `amount` 作为增量增加 `runningTotal` 的值。
```swift
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
@@ -266,13 +268,11 @@ func makeIncrementer(forIncrement amount: Int) -> () -> Int {
}
```
-`makeIncrementor`返回类型为`() -> Int`。这意味着其返回的是一个*函数*,而非一个简单类型的值。该函数在每次调用时不接受参数,只返回一个`Int`类型的值。关于函数返回其他函数的内容,请查看[函数类型作为返回类型](./06_Functions.html#function_types_as_return_types)。
+`makeIncrementor` 返回类型为 `() -> Int`。这意味着其返回的是一个*函数*,而非一个简单类型的值。该函数在每次调用时不接受参数,只返回一个 `Int` 类型的值。关于函数返回其他函数的内容,请查看[函数类型作为返回类型](./06_Functions.html#function_types_as_return_types)。
-`makeIncrementer(forIncrement:)`函数定义了一个初始值为`0`的整型变量`runningTotal`,用来存储当前总计数值。该值为`incrementor`的返回值。
+`makeIncrementer(forIncrement:)` 函数定义了一个初始值为 `0` 的整型变量 `runningTotal`,用来存储当前总计数值。该值为 `incrementor` 的返回值。
-`makeIncrementer(forIncrement:)`有一个`Int`类型的参数,其外部参数名为`forIncrement`,内部参数名为`amount`,该参数表示每次`incrementor`被调用时`runningTotal`将要增加的量。
-
-嵌套函数`incrementor`用来执行实际的增加操作。该函数简单地使`runningTotal`增加`amount`,并将其返回。
+`makeIncrementer(forIncrement:)` 有一个 `Int` 类型的参数,其外部参数名为 `forIncrement`,内部参数名为 `amount`,该参数表示每次 `incrementor` 被调用时 `runningTotal` 将要增加的量。`makeIncrementer` 函数还定义了一个嵌套函数 `incrementor`,用来执行实际的增加操作。该函数简单地使 `runningTotal` 增加 `amount`,并将其返回。
如果我们单独考虑嵌套函数 `incrementer()`,会发现它有些不同寻常:
@@ -283,19 +283,19 @@ func incrementer() -> Int {
}
```
-`incrementer()`函数并没有任何参数,但是在函数体内访问了`runningTotal`和`amount`变量。这是因为它从外围函数捕获了`runningTotal`和`amount`变量的*引用*。捕获引用保证了`runningTotal`和`amount`变量在调用完`makeIncrementer`后不会消失,并且保证了在下一次执行`incrementer`函数时,`runningTotal`依旧存在。
+`incrementer()` 函数并没有任何参数,但是在函数体内访问了 `runningTotal` 和 `amount` 变量。这是因为它从外围函数捕获了 `runningTotal` 和 `amount` 变量的*引用*。捕获引用保证了 `runningTotal` 和 `amount` 变量在调用完 `makeIncrementer` 后不会消失,并且保证了在下一次执行 `incrementer` 函数时,`runningTotal` 依旧存在。
-> 注意
-> 为了优化,如果一个值不会被闭包改变,或者在闭包创建后不会改变,Swift 可能会改为捕获并保存一份对值的拷贝。
+> 注意
+> 为了优化,如果一个值不会被闭包改变,或者在闭包创建后不会改变,Swift 可能会改为捕获并保存一份对值的拷贝。
> Swift 也会负责被捕获变量的所有内存管理工作,包括释放不再需要的变量。
-下面是一个使用`makeIncrementor`的例子:
+下面是一个使用 `makeIncrementor` 的例子:
```swift
let incrementByTen = makeIncrementor(forIncrement: 10)
```
-该例子定义了一个叫做`incrementByTen`的常量,该常量指向一个每次调用会将其`runningTotal`变量增加`10`的`incrementor`函数。调用这个函数多次可以得到以下结果:
+该例子定义了一个叫做 `incrementByTen` 的常量,该常量指向一个每次调用会将其 `runningTotal` 变量增加 `10` 的 `incrementor` 函数。调用这个函数多次可以得到以下结果:
```swift
incrementByTen()
@@ -306,7 +306,7 @@ incrementByTen()
// 返回的值为30
```
-如果你创建了另一个`incrementor`,它会有属于自己的引用,指向一个全新、独立的`runningTotal`变量:
+如果你创建了另一个 `incrementor`,它会有属于自己的引用,指向一个全新、独立的 `runningTotal` 变量:
```swift
let incrementBySeven = makeIncrementor(forIncrement: 7)
@@ -314,7 +314,7 @@ incrementBySeven()
// 返回的值为7
```
-再次调用原来的`incrementByTen`会继续增加它自己的`runningTotal`变量,该变量和`incrementBySeven`中捕获的变量没有任何联系:
+再次调用原来的 `incrementByTen` 会继续增加它自己的 `runningTotal` 变量,该变量和 `incrementBySeven` 中捕获的变量没有任何联系:
```swift
incrementByTen()
@@ -327,9 +327,9 @@ incrementByTen()
## 闭包是引用类型(Closures Are Reference Types)
-上面的例子中,`incrementBySeven`和`incrementByTen`都是常量,但是这些常量指向的闭包仍然可以增加其捕获的变量的值。这是因为函数和闭包都是*引用类型*。
+上面的例子中,`incrementBySeven` 和 `incrementByTen` 都是常量,但是这些常量指向的闭包仍然可以增加其捕获的变量的值。这是因为函数和闭包都是*引用类型*。
-无论你将函数或闭包赋值给一个常量还是变量,你实际上都是将常量或变量的值设置为对应函数或闭包的*引用*。上面的例子中,指向闭包的引用`incrementByTen`是一个常量,而并非闭包内容本身。
+无论你将函数或闭包赋值给一个常量还是变量,你实际上都是将常量或变量的值设置为对应函数或闭包的*引用*。上面的例子中,指向闭包的引用 `incrementByTen` 是一个常量,而并非闭包内容本身。
这也意味着如果你将闭包赋值给了两个不同的常量或变量,两个值都会指向同一个闭包:
@@ -342,10 +342,10 @@ alsoIncrementByTen()
## 逃逸闭包(Escaping Closures)
-当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中*逃逸*。当你定义接受闭包作为参数的函数时,你可以在参数名之前标注`@escaping`,用来指明这个闭包是允许“逃逸”出这个函数的。
+当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中*逃逸*。当你定义接受闭包作为参数的函数时,你可以在参数名之前标注 `@escaping`,用来指明这个闭包是允许“逃逸”出这个函数的。
+
+一种能使闭包“逃逸”出函数的方法是,将这个闭包保存在一个函数外部定义的变量中。举个例子,很多启动异步操作的函数接受一个闭包参数作为 completion handler。这类函数会在异步操作开始之后立刻返回,但是闭包直到异步操作结束后才会被调用。在这种情况下,闭包需要“逃逸”出函数,因为闭包需要在函数返回之后被调用。例如:
-一种能使闭包“逃逸”出函数的方法是,将这个闭包保存在一个函数外部定义的变量中。举个例子,很多启动异步操作的函数接受一个闭包参数作为 completion handler。这类函数会在异步操作开始之后立刻返回,但是闭包直到异步操作结束后才会被调用。在这种情况下,闭包需要“逃逸”出函数,因为闭包需要在函数返回之后被调用。例如:
-
```swift
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
@@ -353,16 +353,16 @@ func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
}
```
-`someFunctionWithEscapingClosure(_:)`函数接受一个闭包作为参数,该闭包被添加到一个函数外定义的数组中。如果你不将这个参数标记为`@escaping`,你将会获得一个编译错误。
+`someFunctionWithEscapingClosure(_:)` 函数接受一个闭包作为参数,该闭包被添加到一个函数外定义的数组中。如果你不将这个参数标记为 `@escaping`,就会得到一个编译错误。
-将一个闭包标记为`@escaping`意味着你必须在闭包中显式地引用`self`。比如说,在下面的代码中,传递到 `someFunctionWithEscapingClosure(_:)` 中的闭包是一个逃逸闭包,这意味着它需要显式地引用`self`。相对的,传递到 `someFunctionWithNonescapingClosure(_:)`中的闭包是一个非逃逸闭包,这意味着它可以隐式引用`self`。
+将一个闭包标记为 `@escaping` 意味着你必须在闭包中显式地引用 `self`。比如说,在下面的代码中,传递到 `someFunctionWithEscapingClosure(_:)` 中的闭包是一个逃逸闭包,这意味着它需要显式地引用 `self`。相对的,传递到 `someFunctionWithNonescapingClosure(_:)` 中的闭包是一个非逃逸闭包,这意味着它可以隐式引用 `self`。
```swift
func someFunctionWithNonescapingClosure(closure: () -> Void) {
closure()
}
-
+
class SomeClass {
var x = 10
func doSomething() {
@@ -370,12 +370,12 @@ class SomeClass {
someFunctionWithNonescapingClosure { x = 200 }
}
}
-
+
let instance = SomeClass()
instance.doSomething()
print(instance.x)
// 打印出 "200"
-
+
completionHandlers.first?()
print(instance.x)
// 打印出 "100"
@@ -386,7 +386,7 @@ print(instance.x)
*自动闭包*是一种自动创建的闭包,用于包装传递给函数作为参数的表达式。这种闭包不接受任何参数,当它被调用的时候,会返回被包装在其中的表达式的值。这种便利语法让你能够省略闭包的花括号,用一个普通的表达式来代替显式的闭包。
-我们经常会*调用*采用自动闭包的函数,但是很少去*实现*这样的函数。举个例子来说,`assert(condition:message:file:line:)`函数接受自动闭包作为它的`condition`参数和`message`参数;它的`condition`参数仅会在 debug 模式下被求值,它的`message`参数仅当`condition`参数为`false`时被计算求值。
+我们经常会*调用*采用自动闭包的函数,但是很少去*实现*这样的函数。举个例子来说,`assert(condition:message:file:line:)` 函数接受自动闭包作为它的 `condition` 参数和 `message` 参数;它的 `condition` 参数仅会在 debug 模式下被求值,它的 `message` 参数仅当 `condition` 参数为 `false` 时被计算求值。
自动闭包让你能够延迟求值,因为直到你调用这个闭包,代码段才会被执行。延迟求值对于那些有副作用(Side Effect)和高计算成本的代码来说是很有益处的,因为它使得你能控制代码的执行时机。下面的代码展示了闭包如何延时求值。
@@ -394,20 +394,20 @@ print(instance.x)
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customersInLine.count)
// 打印出 "5"
-
+
let customerProvider = { customersInLine.remove(at: 0) }
print(customersInLine.count)
// 打印出 "5"
-
+
print("Now serving \(customerProvider())!")
// Prints "Now serving Chris!"
print(customersInLine.count)
// 打印出 "4"
```
-尽管在闭包的代码中,`customersInLine`的第一个元素被移除了,不过在闭包被调用之前,这个元素是不会被移除的。如果这个闭包永远不被调用,那么在闭包里面的表达式将永远不会执行,那意味着列表中的元素永远不会被移除。请注意,`customerProvider`的类型不是`String`,而是`() -> String`,一个没有参数且返回值为`String`的函数。
+尽管在闭包的代码中,`customersInLine` 的第一个元素被移除了,不过在闭包被调用之前,这个元素是不会被移除的。如果这个闭包永远不被调用,那么在闭包里面的表达式将永远不会执行,那意味着列表中的元素永远不会被移除。请注意,`customerProvider` 的类型不是 `String`,而是 `() -> String`,一个没有参数且返回值为 `String` 的函数。
-将闭包作为参数传递给函数时,你能获得同样的延时求值行为。
+将闭包作为参数传递给函数时,你能获得同样的延时求值行为。
```swift
// customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
@@ -418,7 +418,7 @@ serve(customer: { customersInLine.remove(at: 0) } )
// 打印出 "Now serving Alex!"
```
-上面的`serve(customer:)`函数接受一个返回顾客名字的显式的闭包。下面这个版本的`serve(customer:)`完成了相同的操作,不过它并没有接受一个显式的闭包,而是通过将参数标记为`@autoclosure`来接收一个自动闭包。现在你可以将该函数当作接受`String`类型参数(而非闭包)的函数来调用。`customerProvider`参数将自动转化为一个闭包,因为该参数被标记了`@autoclosure`特性。
+上面的 `serve(customer:)` 函数接受一个返回顾客名字的显式的闭包。下面这个版本的 `serve(customer:)` 完成了相同的操作,不过它并没有接受一个显式的闭包,而是通过将参数标记为 `@autoclosure` 来接收一个自动闭包。现在你可以将该函数当作接受 `String` 类型参数(而非闭包)的函数来调用。`customerProvider` 参数将自动转化为一个闭包,因为该参数被标记了 `@autoclosure` 特性。
```swift
// customersInLine is ["Ewa", "Barry", "Daniella"]
@@ -429,10 +429,10 @@ serve(customer: customersInLine.remove(at: 0))
// 打印出 "Now serving Ewa!"
```
-> 注意
-> 过度使用`autoclosures`会让你的代码变得难以理解。上下文和函数名应该能够清晰地表明求值是被延迟执行的。
+> 注意
+> 过度使用 `autoclosures` 会让你的代码变得难以理解。上下文和函数名应该能够清晰地表明求值是被延迟执行的。
-如果你想让一个自动闭包可以“逃逸”,则应该同时使用`@autoclosure`和`@escaping`属性。`@escaping`属性的讲解见上面的[逃逸闭包](#escaping_closures)
+如果你想让一个自动闭包可以“逃逸”,则应该同时使用 `@autoclosure` 和 `@escaping` 属性。`@escaping` 属性的讲解见上面的[逃逸闭包](#escaping_closures)。
```swift
// customersInLine is ["Barry", "Daniella"]
@@ -442,7 +442,7 @@ func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> S
}
collectCustomerProviders(customersInLine.remove(at: 0))
collectCustomerProviders(customersInLine.remove(at: 0))
-
+
print("Collected \(customerProviders.count) closures.")
// 打印出 "Collected 2 closures."
for customerProvider in customerProviders {
@@ -452,5 +452,5 @@ for customerProvider in customerProviders {
// 打印出 "Now serving Daniella!"
```
-在上面的代码中,`collectCustomerProviders(_:)`函数并没有调用传入的`customerProvider`闭包,而是将闭包追加到了`customerProviders`数组中。这个数组定义在函数作用域范围外,这意味着数组内的闭包能够在函数返回之后被调用。因此,`customerProvider`参数必须允许“逃逸”出函数作用域。
+在上面的代码中,`collectCustomerProviders(_:)` 函数并没有调用传入的 `customerProvider` 闭包,而是将闭包追加到了 `customerProviders` 数组中。这个数组定义在函数作用域范围外,这意味着数组内的闭包能够在函数返回之后被调用。因此,`customerProvider` 参数必须允许“逃逸”出函数作用域。
From c966b595d92607cd1243921259a24ae4a880eaaf Mon Sep 17 00:00:00 2001
From: mmoaay
Date: Tue, 20 Sep 2016 14:46:17 +0800
Subject: [PATCH 09/32] =?UTF-8?q?Swift=203.0=20=E6=9B=B4=E6=96=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
增加优先级组(precedence groups)概念
---
source/chapter2/25_Advanced_Operators.md | 69 ++++++++++++++----------
1 file changed, 40 insertions(+), 29 deletions(-)
diff --git a/source/chapter2/25_Advanced_Operators.md b/source/chapter2/25_Advanced_Operators.md
index ee0757f6..04d698de 100644
--- a/source/chapter2/25_Advanced_Operators.md
+++ b/source/chapter2/25_Advanced_Operators.md
@@ -13,6 +13,9 @@
>
> 2.2
> 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-17
+>
+> 3.0
+> 翻译+校对:[mmoaay](https://github.com/mmoaay) 2016-09-20
本页内容包括:
@@ -320,12 +323,15 @@ signedOverflow = signedOverflow &- 1
struct Vector2D {
var x = 0.0, y = 0.0
}
-func + (left: Vector2D, right: Vector2D) -> Vector2D {
- return Vector2D(x: left.x + right.x, y: left.y + right.y)
+
+extension Vector2D {
+ static func + (left: Vector2D, right: Vector2D) -> Vector2D {
+ return Vector2D(x: left.x + right.x, y: left.y + right.y)
+ }
}
```
-该运算符函数被定义为一个全局函数,并且函数的名字与它要进行重载的 `+` 名字一致。因为算术加法运算符是双目运算符,所以这个运算符函数接收两个类型为 `Vector2D` 的参数,同时有一个 `Vector2D` 类型的返回值。
+该运算符函数被定义为 `Vector2D` 上的一个类方法,并且函数的名字与它要进行重载的 `+` 名字一致。因为加法运算并不是一个向量必需的功能,所以这个类方法被定义在 `Vector2D` 的一个扩展中,而不是 `Vector2D` 结构体声明内。而算术加法运算符是双目运算符,所以这个运算符函数接收两个类型为 `Vector2D` 的参数,同时有一个 `Vector2D` 类型的返回值。
在这个实现中,输入参数分别被命名为 `left` 和 `right`,代表在 `+` 运算符左边和右边的两个 `Vector2D` 实例。函数返回了一个新的 `Vector2D` 实例,这个实例的 `x` 和 `y` 分别等于作为参数的两个实例的 `x` 和 `y` 的值之和。
@@ -350,8 +356,10 @@ let combinedVector = vector + anotherVector
要实现前缀或者后缀运算符,需要在声明运算符函数的时候在 `func` 关键字之前指定 `prefix` 或者 `postfix` 修饰符:
```swift
-prefix func - (vector: Vector2D) -> Vector2D {
- return Vector2D(x: -vector.x, y: -vector.y)
+extension Vector2D {
+ static prefix func - (vector: Vector2D) -> Vector2D {
+ return Vector2D(x: -vector.x, y: -vector.y)
+ }
}
```
@@ -372,8 +380,10 @@ let alsoPositive = -negative
复合赋值运算符将赋值运算符(`=`)与其它运算符进行结合。例如,将加法与赋值结合成加法赋值运算符(`+=`)。在实现的时候,需要把运算符的左参数设置成 `inout` 类型,因为这个参数的值会在运算符函数内直接被修改。
```swift
-func += (inout left: Vector2D, right: Vector2D) {
- left = left + right
+extension Vector2D {
+ static func += (left: inout Vector2D, right: Vector2D) {
+ left = left + right
+ }
}
```
@@ -398,11 +408,13 @@ original += vectorToAdd
为了使用等价运算符能对自定义的类型进行判等运算,需要为其提供自定义实现,实现的方法与其它中缀运算符一样:
```swift
-func == (left: Vector2D, right: Vector2D) -> Bool {
- return (left.x == right.x) && (left.y == right.y)
-}
-func != (left: Vector2D, right: Vector2D) -> Bool {
- return !(left == right)
+extension Vector2D {
+ static func == (left: Vector2D, right: Vector2D) -> Bool {
+ return (left.x == right.x) && (left.y == right.y)
+ }
+ static func != (left: Vector2D, right: Vector2D) -> Bool {
+ return !(left == right)
+ }
}
```
@@ -430,18 +442,17 @@ if twoThree == anotherTwoThree {
prefix operator +++ {}
```
-上面的代码定义了一个新的名为 `+++` 的前缀运算符。对于这个运算符,在 Swift 中并没有意义,因此我们针对 `Vector2D` 的实例来定义它的意义。对这个示例来讲,`+++` 被实现为“前缀双自增”运算符。它使用了前面定义的复合加法运算符来让矩阵对自身进行相加,从而让 `Vector2D` 实例的 `x` 属性和 `y` 属性的值翻倍:
+上面的代码定义了一个新的名为 `+++` 的前缀运算符。对于这个运算符,在 Swift 中并没有意义,因此我们针对 `Vector2D` 的实例来定义它的意义。对这个示例来讲,`+++` 被实现为“前缀双自增”运算符。它使用了前面定义的复合加法运算符来让矩阵对自身进行相加,从而让 `Vector2D` 实例的 `x` 属性和 `y` 属性的值翻倍。实现 `+++` 运算符的方式如下:
```swift
-prefix func +++ (inout vector: Vector2D) -> Vector2D {
- vector += vector
- return vector
+extension Vector2D {
+ static prefix func +++ (vector: inout Vector2D) -> Vector2D {
+ vector += vector
+ return vector
+ }
}
-```
-`Vector2D` 的 `+++` 的实现和 `++` 的实现很相似,唯一不同的是前者对自身进行相加,而后者是与另一个值为 `(1.0, 1.0)` 的向量相加。
-```swift
var toBeDoubled = Vector2D(x: 1.0, y: 4.0)
let afterDoubling = +++toBeDoubled
// toBeDoubled 现在的值为 (2.0, 8.0)
@@ -449,20 +460,20 @@ let afterDoubling = +++toBeDoubled
```
-### 自定义中缀运算符的优先级和结合性
+### 自定义中缀运算符的优先级
-自定义的中缀运算符也可以指定优先级和结合性。[优先级和结合性](#precedence_and_associativity)中详细阐述了这两个特性是如何对中缀运算符的运算产生影响的。
+每个自定义中缀运算符都属于某个优先级组。这个优先级组指定了这个运算符和其他中缀运算符的优先级和结合性。[优先级和结合性](#precedence_and_associativity)中详细阐述了这两个特性是如何对中缀运算符的运算产生影响的。
-结合性可取的值有` left`,`right` 和 `none`。当左结合运算符跟其他相同优先级的左结合运算符写在一起时,会跟左边的值进行结合。同理,当右结合运算符跟其他相同优先级的右结合运算符写在一起时,会跟右边的值进行结合。而非结合运算符不能跟其他相同优先级的运算符写在一起。
+而没有明确放入优先级组的自定义中缀运算符会放到一个默认的优先级组内,其优先级高于三元运算符。
-结合性的默认值是 `none`,优先级的默认值 `100`。
-
-以下例子定义了一个新的中缀运算符 `+-`,此运算符的结合性为 `left`,并且它的优先级为 `140`:
+以下例子定义了一个新的自定义中缀运算符 `+-`,此运算符属于 `AdditionPrecedence` 优先组:
```swift
-infix operator +- { associativity left precedence 140 }
-func +- (left: Vector2D, right: Vector2D) -> Vector2D {
- return Vector2D(x: left.x + right.x, y: left.y - right.y)
+infix operator +-: AdditionPrecedence
+extension Vector2D {
+ static func +- (left: Vector2D, right: Vector2D) -> Vector2D {
+ return Vector2D(x: left.x + right.x, y: left.y - right.y)
+ }
}
let firstVector = Vector2D(x: 1.0, y: 2.0)
let secondVector = Vector2D(x: 3.0, y: 4.0)
@@ -470,7 +481,7 @@ let plusMinusVector = firstVector +- secondVector
// plusMinusVector 是一个 Vector2D 实例,并且它的值为 (4.0, -2.0)
```
-这个运算符把两个向量的 `x` 值相加,同时用第一个向量的 `y` 值减去第二个向量的 `y` 值。因为它本质上是属于“相加型”运算符,所以将它的结合性和优先级被分别设置为 `left` 和 `140`,这与 `+` 和 `-` 等默认的中缀“相加型”运算符是相同的。关于 Swift 标准库提供的运算符的结合性与优先级,请参考 [Swift Standard Library Operators Reference](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_StandardLibrary_Operators/index.html#//apple_ref/doc/uid/TP40016054)。
+这个运算符把两个向量的 `x` 值相加,同时用第一个向量的 `y` 值减去第二个向量的 `y` 值。因为它本质上是属于“相加型”运算符,所以将它放置 `+` 和 `-` 等默认的中缀“相加型”运算符相同的优先级组中。关于 Swift 标准库提供的运算符,以及完整的运算符优先级组和结合性设置,请参考 [Swift Standard Library Operators Reference](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_StandardLibrary_Operators/index.html#//apple_ref/doc/uid/TP40016054)。而更多关于优先级组以及自定义操作符和优先级组的语法,请参考[运算符声明](#operator_declaration)
> 注意
> 当定义前缀与后缀运算符的时候,我们并没有指定优先级。然而,如果对同一个值同时使用前缀与后缀运算符,则后缀运算符会先参与运算。
From 2dd84524a70ed2e0db892c539bbadc5d3b2d41fb Mon Sep 17 00:00:00 2001
From: Tony Han
Date: Tue, 20 Sep 2016 16:45:50 +0800
Subject: [PATCH 10/32] Create Types branch.
---
source/chapter3/03_Types.md | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/source/chapter3/03_Types.md b/source/chapter3/03_Types.md
index 8f90eb25..5519834d 100644
--- a/source/chapter3/03_Types.md
+++ b/source/chapter3/03_Types.md
@@ -26,7 +26,7 @@
- [类型继承子句](#type_inheritance_clause)
- [类型推断](#type_inference)
-Swift 语言存在两种类型:命名型类型和复合型类型。命名型类型是指定义时可以给定名字的类型。命名型类型包括类、结构体、枚举和协议。比如,一个用户定义的类 MyClass 的实例拥有类型 MyClass。除了用户定义的命名型类型,Swift 标准库也定义了很多常用的命名型类型,包括那些表示数组、字典和可选值的类型。
+Swift 语言存在两种类型:命名型类型和复合型类型。命名型类型是指定义时可以给定名字的类型。命名型类型包括类、结构体、枚举和协议。比如,一个用户定义的类 `MyClass` 的实例拥有类型 `MyClass`。除了用户定义的命名型类型,Swift 标准库也定义了很多常用的命名型类型,包括那些表示数组、字典和可选值的类型。
那些通常被其它语言认为是基本或原始的数据型类型,比如表示数字、字符和字符串的类型,实际上就是命名型类型,这些类型在 Swift 标准库中是使用结构体来定义和实现的。因为它们是命名型类型,因此你可以按照 [扩展](../chapter2/21_Extensions.html) 和 [扩展声明](05_Declarations.html#extension_declaration) 中讨论的那样,声明一个扩展来增加它们的行为以满足你程序的需求。
@@ -36,7 +36,7 @@ Swift 语言存在两种类型:命名型类型和复合型类型。命名型
> 类型语法
-> *类型* → [*数组类型*](#array-type) | [*字典类型*](#dictionary-type) | [*函数类型*](#function-type) | [*类型标识*](#type-identifier) | [*元组类型*](#tuple-type) | [*可选类型*](#optional-type) | [*隐式解析可选类型*](#implicitly-unwrapped-optional-type) | [*协议合成类型*](#protocol-composition-type) | [*元型类型*](#metatype-type)
+> *类型* → [*数组类型*](#array-type) | [*字典类型*](#dictionary-type) | [*函数类型*](#function-type) | [*类型标识*](#type-identifier) | [*元组类型*](#tuple-type) | [*可选类型*](#optional-type) | [*隐式解析可选类型*](#implicitly-unwrapped-optional-type) | [*协议合成类型*](#protocol-composition-type) | [*元型类型*](#metatype-type) | **任意类型** | **自身类型**
## 类型注解
@@ -53,7 +53,7 @@ func someFunction(a: Int) { /* ... */ }
> 类型注解语法
-> *类型注解* → **:** [*特性列表*](06_Attributes.html#attributes)可选 [*类型*](#type)
+> *类型注解* → **:** [*特性列表*](06_Attributes.html#attributes)可选 **输入输出参数**可选 [*类型*](#type)
## 类型标识符
@@ -87,6 +87,9 @@ var someValue: ExampleModule.MyType
元组类型是使用括号括起来的零个或多个类型,类型间用逗号隔开。
你可以使用元组类型作为一个函数的返回类型,这样就可以使函数返回多个值。你也可以命名元组类型中的元素,然后用这些名字来引用每个元素的值。元素的名字由一个标识符紧跟一个冒号 `(:)` 组成。[函数和多返回值](../chapter2/06_Functions.html#functions_with_multiple_return_values) 章节里有一个展示上述特性的例子。
+
+
+
`Void` 是空元组类型 `()` 的别名。如果括号内只有一个元素,那么该类型就是括号内元素的类型。比如,`(Int)` 的类型是 `Int` 而不是 `(Int)`。所以,只有当元组类型包含的元素个数在两个及以上时才可以命名元组元素。
@@ -354,3 +357,5 @@ let eFloat: Float = 2.71828 // eFloat 的类型为 Float
```
Swift 中的类型推断在单独的表达式或语句上进行。这意味着所有用于类型推断的信息必须可以从表达式或其某个子表达式的类型检查中获取到。
+
+
From c4a033bbba1590143a38263fd0b450c9a0ca9130 Mon Sep 17 00:00:00 2001
From: chenmingjia <564575471@qq.com>
Date: Tue, 20 Sep 2016 17:35:35 +0800
Subject: [PATCH 11/32] Translate Declarations in Swift 3.0.
Translate Declarations in Swift 3.0.
---
source/chapter3/05_Declarations.md | 90 ++++++++++++++++++++++--------
1 file changed, 68 insertions(+), 22 deletions(-)
diff --git a/source/chapter3/05_Declarations.md b/source/chapter3/05_Declarations.md
index 257b7c96..21176915 100755
--- a/source/chapter3/05_Declarations.md
+++ b/source/chapter3/05_Declarations.md
@@ -535,6 +535,14 @@ func someFunction(callback: () throws -> Void) rethrows {
抛出方法不能重写重抛方法,而且抛出方法不能满足协议对于重抛方法的要求。也就是说,重抛方法可以重写抛出方法,而且重抛方法可以满足协议对于抛出方法的要求。
+
+### 永不返回的函数
+
+Swift定义了`Never`类型,它表示函数或者方法不会返回给它的调用者。`Never`返回类型的函数或方法可以称为不归,不归函数、方法要么引发不可恢复的错误,要么永远不停地运作,这会使调用后本应执行得代码就不再执行了。但即使是不归函数、方法,抛错函数和重抛出函数也可以将程序控制转移到合适的`catch`代码块。
+
+不归函数、方法可以在guard语句的else字句中调用,具体讨论在[*Guard语句*](10_Statement.md#guard_statements)。
+你可以重载一个不归方法,但是新的方法必须保持原有的返回类型和没有返回的行为。
+
> 函数声明语法
@@ -571,6 +579,9 @@ func someFunction(callback: () throws -> Void) rethrows {
>
> *默认参数子句* → **=** [*表达式*](04_Expressions.md#expression)
+
+
+
## 枚举声明
@@ -1146,21 +1157,12 @@ subscript (参数列表) -> 返回类型 {
下面的形式声明了一个新的中缀运算符:
```swift
-infix operator 运算符名称 {
- precedence 优先级
- associativity 结合性
-}
+infix operator 运算符名称: 优先级组
```
中缀运算符是二元运算符,置于两个运算对象之间,例如加法运算符(`+`)位于表达式 `1 + 2` 的中间。
-中缀运算符可以选择指定优先级或结合性,或者两者同时指定。
-
-运算符的优先级可以指定在没有括号包围的情况下,运算符与其运算对象如何结合。可以使用上下文相关的关键字 `precedence` 以及紧随其后的优先级数字来指定一个运算符的优先级。优先级可以是 `0` 到 `255` 之间的任何十进制整数。与十进制整数字面量不同的是,它不可以包含任何下划线字符。尽管优先级是一个特定的数字,但它仅用作与另一个运算符的优先级比较大小。也就是说,当两个运算符为同一个运算对象竞争时,例如 `2 + 3 * 5`,优先级更高的运算符将优先参与运算。
-
-运算符的结合性可以指定在没有括号包围的情况下,多个优先级相同的运算符将如何组合。可以使用上下文相关的关键字 `associativity` 以及紧随其后的结合性关键字来指定运算符的结合性,结合性关键字也是上下文相关的,包括 `left`、`right` 和 `none`。左结合运算符以从左到右的顺序进行组合。例如,减法运算符(`-`)具有左结合性,因此 `4 - 5 - 6` 以 `(4 - 5) - 6` 的形式组合,其结果为 `-7`。右结合运算符以从右到左的顺序组合,而设置为 `none` 的运算符不进行组合。具有相同优先级的非结合运算符,不可以互相邻接。例如,表达式 `1 < 2 < 3` 是非法的。
-
-声明时不指定任何优先级或结合性的中缀运算符,优先级为 `100`,结合性为 `none`。
+中缀运算符可以选择指定优先级组。如果没有为运算符设置优先级组,Swift会设置默认优先级组`DefaultPrecedence`,它的优先级比三目优先级`TernaryPrecedence`要高,更多内容参考[*优先级组声明*](#precedence_group_declaration_modifiers)
下面的形式声明了一个新的前缀运算符:
@@ -1197,18 +1199,62 @@ postfix operator 运算符名称 {}
>
> *中缀运算符声明* → **infix** **运算符** [*运算符*](02_Lexical_Structure.md#operator) **{** [*中缀运算符属性*](#infix-operator-attributes)可选 **}**
-
-> *中缀运算符属性* → [*优先级子句*](#precedence-clause)可选 [*结和性子句*](#associativity-clause)可选
->
-> *优先级子句* → **precedence** [*优先级水平*](#precedence-level)
->
-> *优先级水平* → 十进制整数 0 到 255,包含 0 和 255
->
-> *结和性子句* → **associativity** [*结和性*](#associativity)
->
-> *结和性* → **left** | **right** | **none**
+
+> *中缀运算符组* → [*优先级组名称*](#precedence-group-name)
+
+
+
+
+## 优先级组声明
+
+*优先级组声明 (A precedence group declaration)* 会向程序的中缀运算符引入一个全新的优先级组。当没有用圆括号分组时,运算符优先级反应了运算符与它的操作数的关系的紧密程度。
+优先级组的声明如下所示:
+
+```swift
+precedencegroup 优先级组名称{
+ higherThan: 较低优先级组的名称
+ lowerThan: 较高优先级组的名称
+ associativity: 结合性
+ assignment: assignment
+}
+```
+较低优先级组和较高优先级组的名称说明了新建的优先级组是依赖于现存的优先级组的。 `lowerThan`优先级组的属性只可以引用当前模块外的优先级组。当两个运算符为同一个操作数竞争时,比如表达式`2 + 3 * 5`,优先级更高的运算符将优先参与运算。
+
+> 注意
+> 使用较低和较高优先级组相互联系的优先级组必须保持单一层次关系,但它们不必是线性关系。这意味着优先级组也许会有未定义的相关优先级。这些优先级组的运算符在没有用圆括号分组的情况下是不能紧邻着使用的。
+
+Swift定义了大量的优先级组来与标准库的运算符配合使用,例如相加(`+`)和相减(`-`)属于`AdditionPrecedence`组,相乘(`*`)和相除(`/`)属于` MultiplicationPrecedence`组,详细关于Swift标准库中一系列运算符和优先级组内容,参阅[Swift标准库操作符参考](https://developer.apple.com/reference/swift/1851035-swift_standard_library_operators)。
+
+运算符的结合性用于表示在没有圆括号分组的情况下,同样优先级的一系列运算符是如何被分组的。你可以指定运算符的结合性通过上下文关键字`left`、`right`或者`none`,如果没有指定结合性,默认是`none`关键字。左关联性的运算符是从左至右分组的,例如,相减操作符(-)是左关联性的,所以表达式`4 - 5 - 6`被分组为`(4 - 5) - 6`,得出结果-7。右关联性的运算符是从右往左分组的,指定为`none`结合性的运算符就没有结合性。同样优先级没有结合性的运算符不能相邻出现,例如`<`运算符是`none`结合性,那表示`1 < 2 < 3`就不是一个有效表达式。
+
+优先级组的`assignment`表示在包括可选链的操作时的运算符优先级。当设为true时,与优先级组对应的运算符在可选链操作中使用和标准库中赋值运算符同样的分组规则,当设为false或者不设置,该优先级组的运算符与不赋值的运算符遵循同样的可选链规则。
+
+
+> 优先级组声明语法
+
+
+> *优先级组声明* → **precedence**[*优先级组名称*](#precedence-group-name){[*多优先级组属性*](#precedence-group-attributes)可选 }
+
+> *优先级组属性* → [*优先级组属性*](#precedence-group-attribute)[*多优先级组属性*](#precedence-group-attributes)可选 **{** **}**
+
+> *优先级组属性* → [*优先级组关系*](#precedence-group-relation)
+> *优先级组属性* → [*优先级组赋值性*](#precedence-group-assignment)
+> *优先级组属性* → [*优先级组相关性*](#precedence-group-associativity)
+>
+> *优先级组关系* → **higherThan:**[*多优先级组名称*](#precedence-group-names)
+> *优先级组关系* → **lowerThan:**[*多优先级组名称*](#precedence-group-names)
+>
+> *优先级组赋值* → **assignment:**[*布尔字面值*](02_Lexical_Structure.md#boolean-literal)
+
+> *优先级组结合性* → **associativity:left**
+> *优先级组结合性* → **associativity:right**
+> *优先级组结合性* → **associativity:none**
+
+> *多优先级组名称* → [*优先级组名称*](#precedence-group-name) | [*优先级组名称*](#precedence-group-name) | [*优先级组名称*](#precedence-group-name)
+
+> *优先级组名称* →[*标识符*](02_Lexical_Structure.md#identifier)
+
-
## 声明修饰符
声明修饰符都是关键字或上下文相关的关键字,可以修改一个声明的行为或者含义。可以在声明的特性(如果存在)和引入该声明的关键字之间,利用声明修饰符的关键字或上下文相关的关键字指定一个声明修饰符。
From 2f2488877bebb499e27d464e46303e8d2dcebc84 Mon Sep 17 00:00:00 2001
From: chenmingjia <564575471@qq.com>
Date: Tue, 20 Sep 2016 17:40:28 +0800
Subject: [PATCH 12/32] =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=BE=AE=E8=B0=83?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
格式微调
---
source/chapter3/05_Declarations.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/source/chapter3/05_Declarations.md b/source/chapter3/05_Declarations.md
index 21176915..1a714c70 100755
--- a/source/chapter3/05_Declarations.md
+++ b/source/chapter3/05_Declarations.md
@@ -540,7 +540,7 @@ func someFunction(callback: () throws -> Void) rethrows {
Swift定义了`Never`类型,它表示函数或者方法不会返回给它的调用者。`Never`返回类型的函数或方法可以称为不归,不归函数、方法要么引发不可恢复的错误,要么永远不停地运作,这会使调用后本应执行得代码就不再执行了。但即使是不归函数、方法,抛错函数和重抛出函数也可以将程序控制转移到合适的`catch`代码块。
-不归函数、方法可以在guard语句的else字句中调用,具体讨论在[*Guard语句*](10_Statement.md#guard_statements)。
+不归函数、方法可以在guard语句的else字句中调用,具体讨论在[*Guard语句*](10_Statements.md#guard_statements)。
你可以重载一个不归方法,但是新的方法必须保持原有的返回类型和没有返回的行为。
From 2cc398e0c0679a476279f8c85d9fbeb441fa10dd Mon Sep 17 00:00:00 2001
From: chenmingjia <564575471@qq.com>
Date: Tue, 20 Sep 2016 18:01:20 +0800
Subject: [PATCH 13/32] Add Information about guard
Add Information about guard
---
source/chapter3/10_Statements.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/source/chapter3/10_Statements.md b/source/chapter3/10_Statements.md
index c5bcabe3..df38fd2e 100755
--- a/source/chapter3/10_Statements.md
+++ b/source/chapter3/10_Statements.md
@@ -236,14 +236,14 @@ guard 条件 else {
在 `guard` 语句中进行可选绑定的常量或者变量,其可用范围从声明开始直到作用域结束。
-`guard` 语句必须有 `else` 子句,而且必须在该子句中调用标记 `noreturn` 特性的函数,或者使用下面的语句退出当前作用域:
+`guard` 语句必须有 `else` 子句,而且必须在该子句中调用 `Never` 返回类型的函数,或者使用下面的语句退出当前作用域:
* `return`
* `break`
* `continue`
* `throw`
-关于控制转移语句,请参阅 [控制转移语句](#control_transfer_statements)。
+关于控制转移语句,请参阅 [控制转移语句](#control_transfer_statements)。关于`Never`返回类型的函数,请参阅 [永不返回的函数](05_Declarations#functions_that_never_return)。
> guard 语句语法
From c708b0e592a377f16221de7693fea440fd545278 Mon Sep 17 00:00:00 2001
From: chenmingjia <564575471@qq.com>
Date: Tue, 20 Sep 2016 18:07:52 +0800
Subject: [PATCH 14/32] =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=BE=AE=E8=B0=83?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
格式微调
---
source/chapter3/10_Statements.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/source/chapter3/10_Statements.md b/source/chapter3/10_Statements.md
index df38fd2e..ad8b3e75 100755
--- a/source/chapter3/10_Statements.md
+++ b/source/chapter3/10_Statements.md
@@ -243,7 +243,7 @@ guard 条件 else {
* `continue`
* `throw`
-关于控制转移语句,请参阅 [控制转移语句](#control_transfer_statements)。关于`Never`返回类型的函数,请参阅 [永不返回的函数](05_Declarations#functions_that_never_return)。
+关于控制转移语句,请参阅 [控制转移语句](#control_transfer_statements)。关于`Never`返回类型的函数,请参阅 [永不返回的函数](05_Declarations.md#rethrowing_functions_and_methods)。
> guard 语句语法
From 0ff5800a0f4e6a4d356fbbe3b54a29f48c17ba63 Mon Sep 17 00:00:00 2001
From: chenmingjia <564575471@qq.com>
Date: Tue, 20 Sep 2016 18:17:03 +0800
Subject: [PATCH 15/32] =?UTF-8?q?=E5=BE=AE=E8=B0=83?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
微调
---
source/chapter3/05_Declarations.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/source/chapter3/05_Declarations.md b/source/chapter3/05_Declarations.md
index 1a714c70..082166ae 100755
--- a/source/chapter3/05_Declarations.md
+++ b/source/chapter3/05_Declarations.md
@@ -1215,7 +1215,7 @@ precedencegroup 优先级组名称{
higherThan: 较低优先级组的名称
lowerThan: 较高优先级组的名称
associativity: 结合性
- assignment: assignment
+ assignment: 赋值性
}
```
较低优先级组和较高优先级组的名称说明了新建的优先级组是依赖于现存的优先级组的。 `lowerThan`优先级组的属性只可以引用当前模块外的优先级组。当两个运算符为同一个操作数竞争时,比如表达式`2 + 3 * 5`,优先级更高的运算符将优先参与运算。
@@ -1225,9 +1225,9 @@ precedencegroup 优先级组名称{
Swift定义了大量的优先级组来与标准库的运算符配合使用,例如相加(`+`)和相减(`-`)属于`AdditionPrecedence`组,相乘(`*`)和相除(`/`)属于` MultiplicationPrecedence`组,详细关于Swift标准库中一系列运算符和优先级组内容,参阅[Swift标准库操作符参考](https://developer.apple.com/reference/swift/1851035-swift_standard_library_operators)。
-运算符的结合性用于表示在没有圆括号分组的情况下,同样优先级的一系列运算符是如何被分组的。你可以指定运算符的结合性通过上下文关键字`left`、`right`或者`none`,如果没有指定结合性,默认是`none`关键字。左关联性的运算符是从左至右分组的,例如,相减操作符(-)是左关联性的,所以表达式`4 - 5 - 6`被分组为`(4 - 5) - 6`,得出结果-7。右关联性的运算符是从右往左分组的,指定为`none`结合性的运算符就没有结合性。同样优先级没有结合性的运算符不能相邻出现,例如`<`运算符是`none`结合性,那表示`1 < 2 < 3`就不是一个有效表达式。
+运算符的结合性表示在没有圆括号分组的情况下,同样优先级的一系列运算符是如何被分组的。你可以指定运算符的结合性通过上下文关键字`left`、`right`或者`none`,如果没有指定结合性,默认是`none`关键字。左关联性的运算符是从左至右分组的,例如,相减操作符(-)是左关联性的,所以表达式`4 - 5 - 6`被分组为`(4 - 5) - 6`,得出结果-7。右关联性的运算符是从右往左分组的,指定为`none`结合性的运算符就没有结合性。同样优先级没有结合性的运算符不能相邻出现,例如`<`运算符是`none`结合性,那表示`1 < 2 < 3`就不是一个有效表达式。
-优先级组的`assignment`表示在包括可选链的操作时的运算符优先级。当设为true时,与优先级组对应的运算符在可选链操作中使用和标准库中赋值运算符同样的分组规则,当设为false或者不设置,该优先级组的运算符与不赋值的运算符遵循同样的可选链规则。
+优先级组的赋值性表示在包含可选链操作时的运算符优先级。当设为true时,与优先级组对应的运算符在可选链操作中使用和标准库中赋值运算符同样的分组规则,当设为false或者不设置,该优先级组的运算符与不赋值的运算符遵循同样的可选链规则。
> 优先级组声明语法
From 0a36aaf9c189246561c188a8cdaa4e206aaa4cd4 Mon Sep 17 00:00:00 2001
From: Tony Han
Date: Tue, 20 Sep 2016 20:01:26 +0800
Subject: [PATCH 16/32] update swift 3 Types.
update swift 3 Types.
---
source/chapter3/03_Types.md | 113 ++++++++++++++++++++++++------------
1 file changed, 76 insertions(+), 37 deletions(-)
diff --git a/source/chapter3/03_Types.md b/source/chapter3/03_Types.md
index 5519834d..498b36f7 100644
--- a/source/chapter3/03_Types.md
+++ b/source/chapter3/03_Types.md
@@ -88,22 +88,26 @@ var someValue: ExampleModule.MyType
你可以使用元组类型作为一个函数的返回类型,这样就可以使函数返回多个值。你也可以命名元组类型中的元素,然后用这些名字来引用每个元素的值。元素的名字由一个标识符紧跟一个冒号 `(:)` 组成。[函数和多返回值](../chapter2/06_Functions.html#functions_with_multiple_return_values) 章节里有一个展示上述特性的例子。
+当一个元组类型的元素有名字的时候,这个名字就是类型的一部分。
-
+```swift
+var someTuple = (top: 10, bottom: 12) // someTuple 的类型为 (top: Int, bottom: Int)
+someTuple = (top: 4, bottom: 42) // 正确:命名类型匹配
+someTuple = (9, 99) // 正确:命名类型被自动推断
+someTuple = (left: 5, right: 5) // 错误:命名类型不匹配
+```
`Void` 是空元组类型 `()` 的别名。如果括号内只有一个元素,那么该类型就是括号内元素的类型。比如,`(Int)` 的类型是 `Int` 而不是 `(Int)`。所以,只有当元组类型包含的元素个数在两个及以上时才可以命名元组元素。
-> 元组类型语法
+> 元组类型语法
-> *元组类型* → **(** [*元组类型主体*](#tuple-type-body)可选 **)**
-
-> *元组类型主体* → [*元组类型元素列表*](#tuple-type-element-list) **...**可选
+> *元组类型* → **(** [*元组类型元素列表*](#tuple-type-element-list) 可选 **)**
> *元组类型元素列表* → [*元组类型元素*](#tuple-type-element) | [*元组类型元素*](#tuple-type-element) **,** [*元组类型元素列表*](#tuple-type-element-list)
-> *元组类型元素* → [*特性列表*](06_Attributes.html#attributes)可选 **inout**可选 [*类型*](#type) | **inout**可选 [*元素名*](#element-name) [*类型注解*](#type-annotation)
+> *元组类型元素* → [*元素名*](#element-name) [*类型注解*](#type-annotation) | [*类型*](#type)
-> *元素名* → [*标识符*](02_Lexical_Structure.html#identifier)
+> *元素名* → [*标识符*](02_Lexical_Structure.html#identifier)
## 函数类型
@@ -112,22 +116,49 @@ var someValue: ExampleModule.MyType
> `参数类型` -> `返回值类型`
-由于参数类型和返回值类型可以是元组类型,所以函数类型支持多参数与多返回值的函数与方法。
+参数类型是由逗号间隔的类型列表。由于参数类型和返回值类型可以是元组类型,所以函数类型支持多参数与多返回值的函数与方法。
你可以对函数参数使用 `autoclosure` 特性。这会自动将参数表达式转化为闭包,表达式的结果即闭包返回值。这从语法结构上提供了一种便捷:延迟对表达式的求值,直到其值在函数体中被使用。以自动闭包做为参数的函数类型的例子详见 [自动闭包](../chapter2/07_Closures.html#autoclosures) 。
函数类型可以拥有一个可变长参数作为参数类型中的最后一个参数。从语法角度上讲,可变长参数由一个基础类型名字紧随三个点(`...`)组成,如 `Int...`。可变长参数被认为是一个包含了基础类型元素的数组。即 `Int...` 就是 `[Int]`。关于使用可变长参数的例子,请参阅 [可变参数](../chapter2/06_Functions.html#variadic_parameters)。
为了指定一个 `in-out` 参数,可以在参数类型前加 `inout` 前缀。但是你不可以对可变长参数或返回值类型使用 `inout`。关于这种参数的详细讲解请参阅 [输入输出参数](../chapter2/06_Functions.html#in_out_parameters)。
+
+函数和方法中的参数名并不是函数类型的一部分。例如:
+
+```swift
+func someFunction(left: Int, right: Int) {}
+func anotherFunction(left: Int, right: Int) {}
+func functionWithDifferentLabels(top: Int, bottom: Int) {}
+
+var f = someFunction // 函数f的类型为 (Int, Int) -> Void, 而不是 (left: Int, right: Int) -> Void.
+f = anotherFunction // 正确
+f = functionWithDifferentLabels // 正确
+
+func functionWithDifferentArgumentTypes(left: Int, right: String) {}
+func functionWithDifferentNumberOfArguments(left: Int, right: Int, top: Int) {}
+
+f = functionWithDifferentArgumentTypes // 错误
+f = functionWithDifferentNumberOfArguments // 错误
+```
-柯里化函数的函数类型从右向左进行组合。例如,函数类型 `Int -> Int -> Int` 可以理解为 `Int -> (Int -> Int)`,也就是说,该函数类型的参数为 `Int` 类型,其返回类型是一个参数类型为 `Int`,返回类型为 `Int` 的函数类型。关于柯里化函数的讨论见章节 [柯里化函数](05_Declarations.html#curried_functions)。
+如果一个函数类型包涵多个箭头(->),那么函数类型将从右向左进行组合。例如,函数类型 `Int -> Int -> Int` 可以理解为 `Int -> (Int -> Int)`,也就是说,该函数类型的参数为 `Int` 类型,其返回类型是一个参数类型为 `Int`,返回类型为 `Int` 的函数类型。
-函数类型若要抛出错误就必须使用 `throws` 关键字来标记,若要重抛错误则必须使用 `rethrows` 关键字来标记。`throws` 关键字是函数类型的一部分,非抛出函数是抛出函数函数的一个子类型。因此,在使用抛出函数的地方也可以使用不抛出函数。对于柯里化函数,`throws` 关键字只应用于最里层的函数。抛出和重抛函数的相关描述见章节 [抛出函数与方法](05_Declarations.html#throwing_functions_and_methods) 和 [重抛函数与方法](05_Declarations.html#rethrowing_functions_and_methods)。
+函数类型若要抛出错误就必须使用 `throws` 关键字来标记,若要重抛错误则必须使用 `rethrows` 关键字来标记。`throws` 关键字是函数类型的一部分,非抛出函数是抛出函数函数的一个子类型。因此,在使用抛出函数的地方也可以使用不抛出函数。抛出和重抛函数的相关描述见章节 [抛出函数与方法](05_Declarations.html#throwing_functions_and_methods) 和 [重抛函数与方法](05_Declarations.html#rethrowing_functions_and_methods)。
> 函数类型语法
-
-> *函数类型* → [*类型*](#type) **throws**可选 **->** [*类型*](#type)
-> *函数类型* → [*类型*](#type) **rethrows**可选 **->** [*类型*](#type)
+
+> *函数类型* → [*特性列表*](06_Attributes.html#attributes)可选 [*函数类型子句*](#function-type-argument-clause) **throws**可选 **->** [*类型*](#type)
+> *函数类型* → [*特性列表*](06_Attributes.html#attributes)可选 [*函数类型子句*](#function-type-argument-clause) **rethrows** **->** [*类型*](#type)
+
+> *函数类型子句* → ()
+> *函数类型子句* → ([*函数类型参数列表*](#function-type-argument-list)*...*可选)
+
+> *函数类型参数列表* → [*函数类型参数*](function-type-argument) | [*函数类型参数*](function-type-argument), [*函数类型参数列表*](#function-type-argument-list)
+
+> *函数类型参数* → [*特性列表*](06_Attributes.html#attributes)可选 **输入输出参数**可选 [*类型*](#type) | [*参数标签*](#argument-label) [*类型注解*](#type-annotation)
+
+> *参数标签* → [*标识符*](02_Lexical_Structure.html#identifier)
## 数组类型
@@ -197,7 +228,7 @@ var optionalInteger: Optional
在上述两种情况下,变量 `optionalInteger` 都被声明为可选整型类型。注意在类型和 `?` 之间没有空格。
-类型 `Optional` 是一个枚举,有两个成员,`None` 和 `Some(Wrapped)`,用来表示可能有也可能没有的值。任意类型都可以被显式地声明(或隐式地转换)为可选类型。如果你在声明或定义可选变量或属性的时候没有提供初始值,它的值则会自动赋为默认值 `nil`。
+类型 `Optional` 是一个枚举,有两个成员,`none` 和 `some(Wrapped)`,用来表示可能有也可能没有的值。任意类型都可以被显式地声明(或隐式地转换)为可选类型。如果你在声明或定义可选变量或属性的时候没有提供初始值,它的值则会自动赋为默认值 `nil`。
如果一个可选类型的实例包含一个值,那么你就可以使用后缀运算符 `!` 来获取该值,正如下面描述的:
@@ -219,21 +250,29 @@ optionalInteger! // 42
## 隐式解析可选类型
-Swift 语言定义后缀 `!` 作为标准库中命名类型 `ImplicitlyUnwrappedOptional` 的语法糖。换句话说,下面两个声明等价:
+当可以被访问时,Swift 语言定义后缀 `!` 作为标准库中命名类型 `Optional` 的语法糖,来实现自动解包的功能。换句话说,下面两个声明等价:
```swift
var implicitlyUnwrappedString: String!
-var implicitlyUnwrappedString: ImplicitlyUnwrappedOptional
+var explicitlyUnwrappedString: Optional
```
-上述两种情况下,变量 `implicitlyUnwrappedString` 被声明为一个隐式解析可选类型的字符串。注意类型与 `!` 之间没有空格。
-
-你可以在使用可选类型的地方使用隐式解析可选类型。比如,你可以将隐式解析可选类型的值赋给变量、常量和可选属性,反之亦然。
+注意类型与 `!` 之间没有空格。
+
+由于隐式解包修改了包涵其类型的声明语义,嵌套在元组类型或泛型的可选类型(比如字典元素类型或数组元素类型),不能被标记为隐式解包。例如:
+
+```swift
+let tupleOfImplicitlyUnwrappedElements: (Int!, Int!) // 错误
+let implicitlyUnwrappedTuple: (Int, Int)! // 正确
+
+let arrayOfImplicitlyUnwrappedElements: [Int!] // 错误
+let implicitlyUnwrappedArray: [Int]! // 正确
+```
+
+由于隐式解析可选类型和可选类型有同样的表达式`Optional`,你可以在使用可选类型的地方使用隐式解析可选类型。比如,你可以将隐式解析可选类型的值赋给变量、常量和可选属性,反之亦然。
正如可选类型一样,你在声明隐式解析可选类型的变量或属性的时候也不用指定初始值,因为它有默认值 `nil`。
-由于隐式解析可选类型的值会在使用时自动解析,所以没必要使用操作符 `!` 来解析它。也就是说,如果你使用值为 `nil` 的隐式解析可选类型,就会导致运行错误。
-
可以使用可选链式调用来在隐式解析可选表达式上选择性地执行操作。如果值为 `nil`,就不会执行任何操作,因此也不会产生运行错误。
关于隐式解析可选类型的更多细节,请参阅 [隐式解析可选类型](../chapter2/01_The_Basics.html#implicityly_unwrapped_optionals)。
@@ -249,19 +288,19 @@ var implicitlyUnwrappedString: ImplicitlyUnwrappedOptional
协议合成类型的形式如下:
-> protocol<`Protocol 1`, `Procotol 2`>
+> `Protocol 1` & `Procotol 2`
-协议合成类型允许你指定一个值,其类型符合多个协议的要求且不需要定义一个新的命名型协议来继承它想要符合的各个协议。比如,协议合成类型 `protocol` 等效于一个从 `Protocol A`,`Protocol B`, `Protocol C` 继承而来的新协议 `Protocol D`,很显然这样做有效率的多,甚至不需引入一个新名字。
+协议合成类型允许你指定一个值,其类型符合多个协议的要求且不需要定义一个新的命名型协议来继承它想要符合的各个协议。比如,协议合成类型 `Protocol A & Protocol B & Protocol C` 等效于一个从 `Protocol A`,`Protocol B`, `Protocol C` 继承而来的新协议 `Protocol D`,很显然这样做有效率的多,甚至不需引入一个新名字。
-协议合成列表中的每项必须是协议名或协议合成类型的类型别名。如果列表为空,它就会指定一个空协议合成列表,每个类型都符合它。
+协议合成列表中的每项必须是协议名或协议合成类型的类型别名。
> 协议合成类型语法
-> *协议合成类型* → **protocol** **<** [*协议标识符列表*](#protocol-identifier-list)可选 **>**
-
-> *协议标识符列表* → [*协议标识符*](#protocol-identifier) | [*协议标识符*](#protocol-identifier) **,** [*协议标识符列表*](#protocol-identifier-list)
+> *协议合成类型* → [*协议标识符*](#protocol-identifier) & [*协议合成延续*](#protocol-composition-continuation)
+
+> *协议合成延续* → [*协议标识符*](#protocol-identifier) | [*协议合成类型*](#protocol-composition-type)
-> *协议标识符* → [*类型标识符*](#type-identifier)
+> *协议标识符* → [*类型标识符*](#type-identifier)
## 元类型
@@ -270,7 +309,7 @@ var implicitlyUnwrappedString: ImplicitlyUnwrappedOptional
类、结构体或枚举类型的元类型是相应的类型名紧跟 `.Type`。协议类型的元类型——并不是运行时符合该协议的具体类型——而是该协议名字紧跟 `.Protocol`。比如,类 `SomeClass` 的元类型就是 `SomeClass.Type`,协议 `SomeProtocol` 的元类型就是 `SomeProtocal.Protocol`。
-你可以使用后缀 `self` 表达式来获取类型。比如,`SomeClass.self` 返回 `SomeClass` 本身,而不是 `SomeClass` 的一个实例。同样,`SomeProtocol.self` 返回 `SomeProtocol` 本身,而不是运行时符合 `SomeProtocol` 的某个类型的实例。还可以对类型的实例使用 `dynamicType` 表达式来获取该实例在运行阶段的类型,如下所示:
+你可以使用后缀 `self` 表达式来获取类型。比如,`SomeClass.self` 返回 `SomeClass` 本身,而不是 `SomeClass` 的一个实例。同样,`SomeProtocol.self` 返回 `SomeProtocol` 本身,而不是运行时符合 `SomeProtocol` 的某个类型的实例。还可以对类型的实例使用 `type(of:)` 表达式来获取该实例在运行阶段的类型,如下所示:
```swift
class SomeBaseClass {
@@ -286,19 +325,19 @@ class SomeSubClass: SomeBaseClass {
let someInstance: SomeBaseClass = SomeSubClass()
// someInstance 在编译期是 SomeBaseClass 类型,
// 但是在运行期则是 SomeSubClass 类型
-someInstance.dynamicType.printClassName()
+type(of: someInstance).printClassName()
// 打印 “SomeSubClass”
```
可以使用恒等运算符(`===` 和 `!==`)来测试一个实例的运行时类型和它的编译时类型是否一致。
```swift
-if someInstance.dynamicType === SomeBaseClass.self {
- print("The dynamic type of someInstance is SomeBaseCass")
-} else {
- print("The dynamic type of someInstance isn't SomeBaseClass")
-}
-// 打印 “The dynamic type of someInstance isn't SomeBaseClass”
+if type(of: someInstance) === someInstance.self {
+ print("The dynamic and static type of someInstance are the same")
+} else {
+ print("The dynamic and static type of someInstance are different")
+}
+// 打印 "The dynamic and static type of someInstance are different"
```
可以使用初始化表达式从某个类型的元类型构造出一个该类型的实例。对于类实例,被调用的构造器必须使用 `required` 关键字标记,或者整个类使用 `final` 关键字标记。
@@ -324,7 +363,7 @@ let anotherInstance = metatype.init(string: "some string")
## 类型继承子句
-类型继承子句被用来指定一个命名型类型继承自哪个类、采纳哪些协议。类型继承子句也用来指定一个类类型专属协议。类型继承子句开始于冒号 `:`,其后是类的超类或者一系列类型标识符。
+类型继承子句被用来指定一个命名型类型继承自哪个类、采纳哪些协议。类型继承子句也用来指定一个类类型专属协议。类型继承子句开始于冒号 `:`,其后是所需要的类、类型标识符列表或两者都有。
类可以继承单个超类,采纳任意数量的协议。当定义一个类时,超类的名字必须出现在类型标识符列表首位,然后跟上该类需要采纳的任意数量的协议。如果一个类不是从其它类继承而来,那么列表可以以协议开头。关于类继承更多的讨论和例子,请参阅 [继承](../chapter2/13_Inheritance.html)。
From 17757b41b4973a1ef8f72751c571eee1e8eeeae0 Mon Sep 17 00:00:00 2001
From: chenmingbiao
Date: Wed, 21 Sep 2016 10:18:20 +0800
Subject: [PATCH 17/32] update chapter Protocols to swift 3.0
---
source/chapter2/22_Protocols.md | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md
index ad3a04ee..c955955c 100644
--- a/source/chapter2/22_Protocols.md
+++ b/source/chapter2/22_Protocols.md
@@ -10,10 +10,13 @@
> 2.1
> 翻译:[小铁匠Linus](https://github.com/kevin833752)
-> 校对:[shanks](http://codebuild.me),2015-11-01
+> 校对:[shanks](http://codebuild.me)
>
> 2.2
-> 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-16
+> 翻译+校对:[SketchK](https://github.com/SketchK)
+>
+> 3.0
+> 校对:[CMB](https://github.com/chenmingbiao)
本页包含内容:
@@ -614,7 +617,7 @@ protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
## 协议合成
-有时候需要同时采纳多个协议,你可以将多个协议采用 `protocol` 这样的格式进行组合,称为 *协议合成(protocol composition)*。你可以在 `<>` 中罗列任意多个你想要采纳的协议,以逗号分隔。
+有时候需要同时采纳多个协议,你可以将多个协议采用 `SomeProtocol & AnotherProtocol` 这样的格式进行组合,称为 *协议合成(protocol composition)*。你可以罗列任意多个你想要采纳的协议,以与符号(`&`)分隔。
下面的例子中,将 `Named` 和 `Aged` 两个协议按照上述语法组合成一个协议,作为函数参数的类型:
@@ -629,17 +632,17 @@ struct Person: Named, Aged {
var name: String
var age: Int
}
-func wishHappyBirthday(celebrator: protocol) {
- print("Happy birthday \(celebrator.name) - you're \(celebrator.age)!")
+func wishHappyBirthday(to celebrator: Named & Aged) {
+ print("Happy birthday, \(celebrator.name), you're \(celebrator.age)!")
}
let birthdayPerson = Person(name: "Malcolm", age: 21)
-wishHappyBirthday(birthdayPerson)
+wishHappyBirthday(to: birthdayPerson)
// 打印 “Happy birthday Malcolm - you're 21!”
```
`Named` 协议包含 `String` 类型的 `name` 属性。`Aged` 协议包含 `Int` 类型的 `age` 属性。`Person` 结构体采纳了这两个协议。
-`wishHappyBirthday(_:)` 函数的参数 `celebrator` 的类型为 `protocol`。这意味着它不关心参数的具体类型,只要参数符合这两个协议即可。
+`wishHappyBirthday(_:)` 函数的参数 `celebrator` 的类型为 `Named & Aged`。这意味着它不关心参数的具体类型,只要参数符合这两个协议即可。
上面的例子创建了一个名为 `birthdayPerson` 的 `Person` 的实例,作为参数传递给了 `wishHappyBirthday(_:)` 函数。因为 `Person` 同时符合这两个协议,所以这个参数合法,函数将打印生日问候语。
From 1ad8b08ec60b2e1d8b0d8139ecdc0585664ed9b2 Mon Sep 17 00:00:00 2001
From: shanks
Date: Fri, 23 Sep 2016 08:54:22 +0800
Subject: [PATCH 18/32] Update README.md
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
更新到Swift3.0
---
README.md | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 0c8dbb3d..08a83afa 100755
--- a/README.md
+++ b/README.md
@@ -13,7 +13,26 @@
# 当前阶段
-已经更新到 Swift 2.2。
+
+
+已经更新到 Swift 3.0。 2016-09-23
+
+# 3.0 译者记录
+相关[issue](https://github.com/numbbbbb/the-swift-programming-language-in-chinese/issues/628)
+- Functions: [crayygy](https://github.com/crayygy)
+- Control Flow: [Realank](https://github.com/Realank)
+- Closures: [LanfordCai](https://github.com/LanfordCai)
+- Protocols: [chenmingbiao](https://github.com/chenmingbiao)
+- The Basics:[chenmingbiao](https://github.com/chenmingbiao)
+- Advanced Operators: [mmoaay](https://github.com/mmoaay)
+
+Language Reference:
+- Attributes: [WhoJave](https://github.com/WhoJave)
+- Statements: [chenmingjia](https://github.com/chenmingjia)
+- Declarations: [chenmingjia](https://github.com/chenmingjia)
+- Expressions: [chenmingjia](https://github.com/chenmingjia)
+- Types: [lettleprince](https://github.com/lettleprince)
+- Generic Parameters and Arguments: [chenmingjia](https://github.com/chenmingjia)
# 2.1 & 2.2 译者记录
From d5629a91e697427cf728225e9e4b0af880a7a66b Mon Sep 17 00:00:00 2001
From: chenmingbiao
Date: Fri, 23 Sep 2016 10:09:00 +0800
Subject: [PATCH 19/32] =?UTF-8?q?=E6=B7=BB=E5=8A=A0protocol=E7=AB=A0?=
=?UTF-8?q?=E8=8A=82=E6=A0=A1=E5=AF=B9=E6=97=A5=E6=9C=9F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
source/chapter2/22_Protocols.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/source/chapter2/22_Protocols.md b/source/chapter2/22_Protocols.md
index c955955c..deb7a420 100644
--- a/source/chapter2/22_Protocols.md
+++ b/source/chapter2/22_Protocols.md
@@ -17,6 +17,8 @@
>
> 3.0
> 校对:[CMB](https://github.com/chenmingbiao)
+>
+> 版本日期:2016-09-13
本页包含内容:
From 1cd9134cbed8be47ebc963668ee6d310b9c6b03c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A2=81=E6=9D=B0?=
Date: Fri, 23 Sep 2016 10:32:06 +0800
Subject: [PATCH 20/32] Update README.md
---
source/README.md | 90 +++++++++---------------------------------------
1 file changed, 17 insertions(+), 73 deletions(-)
diff --git a/source/README.md b/source/README.md
index d1cf2e96..0990157d 100755
--- a/source/README.md
+++ b/source/README.md
@@ -1,76 +1,20 @@
-> 已同步更新到 Swift 2.2
+> 2016.9.23: 已经更新到 Swift 3.0。
-# 2.0 新的开始
+# 3.0 译者记录
+相关[issue](https://github.com/numbbbbb/the-swift-programming-language-in-chinese/issues/628)
+- Functions: [crayygy](https://github.com/crayygy)
+- Control Flow: [Realank](https://github.com/Realank)
+- Closures: [LanfordCai](https://github.com/LanfordCai)
+- Protocols: [chenmingbiao](https://github.com/chenmingbiao)
+- The Basics:[chenmingbiao](https://github.com/chenmingbiao)
+- Advanced Operators: [mmoaay](https://github.com/mmoaay)
-> Swift 兴趣交流群:`131595168`, `146932759`, `151336833`, `153549217`. **加入一个群即可,请勿重复添加**
+Language Reference:
+- Attributes: [WhoJave](https://github.com/WhoJave)
+- Statements: [chenmingjia](https://github.com/chenmingjia)
+- Declarations: [chenmingjia](https://github.com/chenmingjia)
+- Expressions: [chenmingjia](https://github.com/chenmingjia)
+- Types: [lettleprince](https://github.com/lettleprince)
+- Generic Parameters and Arguments: [chenmingjia](https://github.com/chenmingjia)
-> 订阅 Swift 开发者周报,每周获取最新 Swift 资源
-
-
-> 如果您觉得这个项目不错,请点击Star一下,您的支持是我们最大的动力。
-
-
-## 1
-
-开源项目完成难,维护更难。
-
-大家看到的是发布时的瞩目和荣耀,却没有看到项目本身质量不高、错误频出。这并不是翻译者和校对者的问题,他们已经付出了足够的努力。真正的问题在我,没有建立起长期的维护团队,因此后期的校对和更新都难以实施。
-
-1.0发布之后,我们就再也没能和苹果的文档同步。语法错误、编译不通过、语言不通顺,阅读量直线下降,最低时每天只有不到1000人访问。
-
-6月9日,calvingit发了一个issue“准备翻译2.0版本吗”,我没有回复,应该已经没人关注这个项目了吧,我想。
-
-## 2
-
-我错了。
-
-
-
-
-
-
-
-
-
-在我没有任何回复的情况下,不到一天时间,有五位朋友报名。看到这些回复的时候我真的很惊讶,也很感动,无论这个项目存在多少问题,只要有人关注,有人愿意为它付出,那我还有什么理由放弃呢?
-
-6月28日8点55分,Swift 2.0翻译正式启动。按下发送按钮后,我不停的刷新页面,半个小时过去了,一个回复都没有。“还是不行啊”“如果再过一个小时没人回复我就把issue删掉”,类似的念头不断出现,又不断消失。
-
-9:35,xtymichael第一个回复,而且一下就认领了三篇!接下来就是不断的回复认领,到中午已经有超过一半章节被认领。
-
-第二天早晨,37个章节全部认领完毕。
-
-## 3
-
-经过一个多月的努力,我们终于完成了文档的更新。听起来似乎没什么,确实,从1到n总是没有从0到1那么振奋人心。不过真正参与了才知道,修改往往比创造更麻烦,一个需要耐心,一个需要激情,前者往往得不到应有的重视。
-
-但是我还是想尽最大可能去感谢他们,这个项目能走到今天,靠的不是我,是那个issue,是那些回复,是这几十个兄弟在工作学习的空闲敲下的每一个字符。而我能做的,只是在每篇文章的开头,那个所有人都会忽略的地方,加上他们的ID。
-
-下次你再打开这篇文档,可以多看看那些列在最上方的ID,哪怕不去follow和star,只是看一眼就好。他们的所有努力和付出,就存在于这短暂的一瞥中。
-
-Swift 2.0 参与者名单(按照章节顺序):
-- [xtymichael](https://github.com/xtymichael)
-- [AlanMelody](https://github.com/AlanMelody)
-- [DianQK](https://github.com/DianQK)
-- [dreamkidd](https://github.com/dreamkidd)
-- [100mango](https://github.com/100mango)
-- [futantan](https://github.com/futantan)
-- [SkyJean](https://github.com/SkyJean)
-- [yangsiy](https://github.com/yangsiy)
-- [shanksyang](https://github.com/shanksyang)
-- [chenmingbiao](https://github.com/chenmingbiao)
-- [Channe](https://github.com/Channe)
-- [lyojo](https://github.com/lyojo)
-- [SergioChan](https://github.com/SergioChan)
-- [mmoaay](https://github.com/mmoaay)
-- [buginux](https://github.com/buginux)
-- [KYawn](https://github.com/KYawn)
-- [EudeMorgen](https://github.com/EudeMorgen)
-- [littledogboy](https://github.com/littledogboy)
-- [Lenhoon](https://github.com/Lenhoon)
-- [ray16897188](https://github.com/ray16897188)
-- [wardenNScaiyi](https://github.com/wardenNScaiyi)
-- [miaosiqi](https://github.com/miaosiqi)
-- [Realank](https://github.com/Realank)
-
-最后,感谢[极客学院](http://wiki.jikexueyuan.com)提供的wiki系统,在国内访问起来速度很快,优化后的样式看起来也更舒服。
+感谢阅读!
From 9250e9132e1c2000b571fd52e8dc99f1c586e64c Mon Sep 17 00:00:00 2001
From: floydzhang1984
Date: Fri, 23 Sep 2016 14:03:06 +0800
Subject: [PATCH 21/32] Add 3.0 cover image
---
cover/cover_3.0.jpg | Bin 0 -> 903707 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 cover/cover_3.0.jpg
diff --git a/cover/cover_3.0.jpg b/cover/cover_3.0.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..76bcfd84a3bd81b7b913f5ba576cd6c45d3143d5
GIT binary patch
literal 903707
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