Files
the-swift-programming-langu…/source/chapter2/Closures.md
2014-06-05 15:21:00 +08:00

91 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 闭包
闭包是功能性自包含模块可以在代码中被传递和使用。Swift 中的闭包与 C 和 Objective-C 中的 `blocks` 以及 其他一些编程语言中的 `lambdas` 比较相似。
闭包可以 **捕获** 和存储其所在上下文中任意常量和变量的引用。这就是所谓的闭合并包裹着这些常量和变量俗称闭包。Swift 会为您管理在 **捕获** 过程中涉及到的内存操作。
> 注意:
>
> 如果您不熟悉 **捕获** (capturing) 这个概念也不用担心,后面会详细对其进行介绍。
`函数` 章节中介绍的全局和嵌套函数实际上也是特殊的闭包,闭包采取如下三种形式之一:
* 全局函数是一个有名字但不会捕获任何值的闭包
* 嵌套函数是一个有名字并可以捕获其封闭函数域内值的闭包
* 闭包表达式是一个利用轻量级语法所写的可以捕获其上下文中变量或常量值的没有名字的闭包
Swift 的闭包表达式拥有简洁的风格,并鼓励在常见场景中进行语法优化,主要优化如下:
* 利用上下文推断参数和返回值类型
* 对于单表达式闭包可以不写return
* 简单的参数命名
* Trailing 闭包语法
### 闭包表达式
嵌套函数是一个在较复杂函数中方便进行命名和定义自包含代码模块的方式。当然,有时候撰写小巧的没有完整定义和命名的类函数结构也是很有用处的,尤其是在您处理一些函数的时候需要将另外一些函数作为该函数的参数时。
闭包表达式是一种利用简洁语法构建内联闭包的方式。闭包表达式提供了一些语法优化,使得撰写闭包变得简单明了。下面闭包表达式的例子通过使用几次迭代展示了 `sort` 函数定义和语法优化的方式。每一次迭代都用更简洁的方式描述了相同的功能。
##### `Sort` 函数
Swift 标准库提供了 `sort` 函数,会根据您提供的排序闭包将已知类型数组中的值进行排序。一旦排序完成,函数会返回一个与原数大小相同的新数组,该数组中包含已经正确排序的同类型元素。
下面的闭包表达式示例使用 `sort` 函数对一个 **String** 类型的数组进行字母逆序排序,以下是初始数组值:
```
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
```
该例子对一个 **String** 类型的数组进行排序,因此排序闭包需为 `(String, String) -> Bool` 类型的函数。
提供排序闭包的一种方式是撰写一个正确类型的普通函数并将其作为 `sort` 函数的第二个参数传入:
```
func backwards(s1: String, s2: String) -> Bool {
return s1 > s2
}
var reversed = sort(names, backwards)
// reversed is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
```
如果第一个字符串 (s1) 大于第二个字符串 (s2)`backwards` 函数则返回 `true`,表示在新的数组中 s1 应该出现在 s2 前。字符中的 "大于" 表示 "按照字母顺序后出现"。这意味着字母 "B" 大于字母 "A", 字符串 "Tom" 大于字符串 "Tim"。其将进行字母逆序排序,"Barry" 将会排在 "Alex" 之后。
然而,这是一个相当冗长的方式,本质上只是写了一个单表达式函数 (a > b)。在下面的例子中,利用闭合表达式语法可以更好的构造一个内联排序闭包。
##### 闭包表达式语法
闭包表达式语法有如下一般形式:
```
{ (parameters) -> returnType in
statements
}
```
闭包表达式语法可以使用常量、变量和 `inout` 类型作为参数,不提供默认值。也可以在参数列表的最后使用可变参数。元组也可以作为参数和返回值。
下面的例子展示了之前 `backwards` 函数对应的闭包表达式版本的代码:
```
reversed = sort(names, { (s1: String, s2: String) -> Bool in
return s1 > s2
})
```
需要注意的是内联闭包参数和返回值类型声明与 `backwards` 函数类型声明相同。在这两种方式中,都写成了 (s1: String, s2: String) -> Bool。然而在内联闭包表达式中函数和返回值类型都写在大括号内而不是大括号外。
闭包的函数体部分由关键字 `in` 引入。该关键字表示闭包的参数和返回值类型定义已经完成,闭包函数体即将开始。
因为这个闭包的函数体部分如此短以至于可以将其改写成一行代码:
```
reversed = sort(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } )
```
这说明 `sort` 函数的整体调用保持不变,已对圆括号仍然包裹住了函数中整个参数集合。而其中一个参数现在变成了内联闭包(相比于 `backwards` 版本的代码)。