update chapter 'Closure' to swift 3.0

This commit is contained in:
Cai Linfeng
2016-09-19 23:33:16 +08:00
parent 64dd00b6f6
commit ed9a67ba9d

View File

@ -14,6 +14,9 @@
>
> 2.2
> 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-12
>
> 3.0
> 翻译:[Lanford](https://github.com/LanfordCai) 2016-09-19
本页包含内容:
@ -55,9 +58,9 @@ Swift 的闭包表达式拥有简洁的风格,并鼓励在常见场景中进
<a name="the_sorted_function"></a>
### 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"]
@ -92,8 +95,7 @@ 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(_:_:)` 函数对应的闭包表达式版本的代码:
@ -129,7 +131,7 @@ reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )
尽管如此,你仍然可以明确写出有着完整格式的闭包。如果完整格式的闭包能够提高代码的可读性,则我们更鼓励采用完整格式的闭包。而在 `sorted(by:)` 方法这个例子里,显然闭包的目的就是排序。由于这个闭包是为了处理字符串数组的排序,因此读者能够推测出这个闭包是用于字符串处理的。
<a name="implicit_returns_from_single_expression_closures"></a>
### 单表达式闭包隐式返回Implicit Return From Single-Expression Clossures
### 单表达式闭包隐式返回Implicit Returns From Single-Expression Closures
单行表达式闭包可以通过省略 `return` 关键字来隐式返回单行表达式的结果,如上版本的例子可以改写为:
@ -152,8 +154,8 @@ reversedNames = names.sorted(by: { $0 > $1 } )
在这个例子中,`$0``$1`表示闭包中第一个和第二个 `String` 类型的参数。
<a name="operator_functions"></a>
### 运算符函数Operator Functions
<a name="operator_methods"></a>
### 运算符方法Operator Methods
实际上还有一种更简短的方式来编写上面例子中的闭包表达式。Swift 的 `String` 类型定义了关于大于号(`>`)的字符串实现,其作为一个函数接受两个 `String` 类型的参数并返回 `Bool` 类型的值。而这正好与 `sorted(by:)` 方法的参数需要的函数类型相符合。因此你可以简单地传递一个大于号Swift 可以自动推断出你想使用大于号的字符串函数实现:
@ -161,12 +163,12 @@ reversedNames = names.sorted(by: { $0 > $1 } )
reversedNames = names.sorted(by: >)
```
更多关于运算符表达式的内容请查看[运算符函数](./25_Advanced_Operators.html#operator_functions)。
更多关于运算符方法的内容请查看[运算符方法](./25_Advanced_Operators.html#operator_methods)。
<a name="trailing_closures"></a>
## 尾随闭包Trailing Closures
如果你需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用*尾随闭包*来增强函数的可读性。尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用:
如果你需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用*尾随闭包*来增强函数的可读性。尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。在使用尾随闭包时,你不用写出它的参数标签
```swift
func someFunctionThatTakesAClosure(closure: () -> Void) {
@ -212,7 +214,7 @@ let numbers = [16, 58, 510]
如上代码创建了一个整型数位和它们英文版本名字相映射的字典。同时还定义了一个准备转换为字符串数组的整型数组。
你现在可以通过传递一个尾随闭包给`numbers``map(_:)`方法来创建对应的字符串版本数组:
你现在可以通过传递一个尾随闭包给 `numbers` 数组的 `map(_:)` 方法来创建对应的字符串版本数组:
```swift
let strings = numbers.map {
@ -231,7 +233,7 @@ let strings = numbers.map {
`map(_:)` 为数组中每一个元素调用了一次闭包表达式。你不需要指定闭包的输入参数 `number` 的类型,因为可以通过要映射的数组类型进行推断。
在该例中,局部变量`number`的值由闭包中的`number`参数获得,因此可以在闭包函数体内对其进行修改,(闭包或者函数的参数总是常量),闭包表达式指定了返回类型为`String`,以表明存储映射值的新数组类型为`String`
在该例中,局部变量 `number` 的值由闭包中的 `number` 参数获得因此可以在闭包函数体内对其进行修改,(闭包或者函数的参数总是常量)闭包表达式指定了返回类型为 `String`,以表明存储映射值的新数组类型为 `String`
闭包表达式在每次被调用的时候创建了一个叫做 `output` 的字符串并返回。其使用求余运算符(`number % 10`)计算最后一位数字并利用 `digitNames` 字典获取所映射的字符串。这个闭包能够用于创建任意正整数的字符串表示。
@ -270,9 +272,7 @@ func makeIncrementer(forIncrement amount: Int) -> () -> Int {
`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()`,会发现它有些不同寻常:
@ -353,7 +353,7 @@ func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
}
```
`someFunctionWithEscapingClosure(_:)`函数接受一个闭包作为参数,该闭包被添加到一个函数外定义的数组中。如果你不将这个参数标记为`@escaping`你将会获得一个编译错误。
`someFunctionWithEscapingClosure(_:)` 函数接受一个闭包作为参数,该闭包被添加到一个函数外定义的数组中。如果你不将这个参数标记为 `@escaping`就会得到一个编译错误。
将一个闭包标记为 `@escaping` 意味着你必须在闭包中显式地引用 `self`。比如说,在下面的代码中,传递到 `someFunctionWithEscapingClosure(_:)` 中的闭包是一个逃逸闭包,这意味着它需要显式地引用 `self`。相对的,传递到 `someFunctionWithNonescapingClosure(_:)` 中的闭包是一个非逃逸闭包,这意味着它可以隐式引用 `self`
@ -432,7 +432,7 @@ serve(customer: customersInLine.remove(at: 0))
> 注意
> 过度使用 `autoclosures` 会让你的代码变得难以理解。上下文和函数名应该能够清晰地表明求值是被延迟执行的。
如果你想让一个自动闭包可以“逃逸”,则应该同时使用`@autoclosure``@escaping`属性。`@escaping`属性的讲解见上面的[逃逸闭包](#escaping_closures)
如果你想让一个自动闭包可以“逃逸”,则应该同时使用 `@autoclosure``@escaping` 属性。`@escaping` 属性的讲解见上面的[逃逸闭包](#escaping_closures)
```swift
// customersInLine is ["Barry", "Daniella"]