From 7d06431a17927c43b17dcf9623ac44f54ae788a9 Mon Sep 17 00:00:00 2001 From: lyuka Date: Wed, 11 Jun 2014 22:04:10 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A0=A1=E5=AF=B9=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/07_Closures.md | 84 +++++++++++++++++----------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/source/chapter2/07_Closures.md b/source/chapter2/07_Closures.md index 8cce8708..f74fa8b9 100644 --- a/source/chapter2/07_Closures.md +++ b/source/chapter2/07_Closures.md @@ -1,23 +1,23 @@ -# 闭包 +# 闭包(Closures) ----------------- -本页内容包含: +本页包含内容: -- 闭包表达式 -- 尾随闭包 -- 值捕获 -- 闭包是引用类型 +- [闭包表达式(Closure Expressions)](#closure_expressions) +- [尾随闭包(Trailing Closures)](#trailing_closures) +- [值捕获(Capturing Values)](#capturing_values) +- [闭包是引用类型(Closures Are Reference Types)](#closures_are_reference_types) 闭包是自包含的函数代码块,可以在代码中被传递和使用。 -Swift 中的闭包与 C 和 Objective-C 中的`blocks` (代码块) 以及其他一些编程语言中的`lambdas` (匿名函数) 比较相似。 +Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的 lambdas 函数比较相似。 -闭包可以**捕获**和存储其所在上下文中任意常量和变量的引用。 -这就是所谓的闭合并包裹着这些常量和变量,俗称闭包。Swift 会为您管理在**捕获**过程中涉及到的所有内存操作。 +闭包可以捕获和存储其所在上下文中任意常量和变量的引用。 +这就是所谓的闭合并包裹着这些常量和变量,俗称闭包。Swift 会为您管理在捕获过程中涉及到的所有内存操作。 > 注意: -> 如果您不熟悉**捕获** (capturing) 这个概念也不用担心,您可以在 [捕获值](#capturing_values) 章节对其进行详细了解。 +> 如果您不熟悉捕获(capturing)这个概念也不用担心,您可以在 [值捕获](#capturing_values) 章节对其进行详细了解。 -在`函数` (**这里需要函数章节提供相应链接进行配合**) 章节中介绍的全局和嵌套函数实际上也是特殊的闭包,闭包采取如下三种形式之一: +在[函数](../chapter2/06_Function.html) 章节中介绍的全局和嵌套函数实际上也是特殊的闭包,闭包采取如下三种形式之一: * 全局函数是一个有名字但不会捕获任何值的闭包 * 嵌套函数是一个有名字并可以捕获其封闭函数域内值的闭包 @@ -28,14 +28,14 @@ Swift 的闭包表达式拥有简洁的风格,并鼓励在常见场景中进 * 利用上下文推断参数和返回值类型 * 隐式返回单表达式闭包,即单表达式闭包可以省略`return`关键字 * 参数名称缩写 -* 尾随 (Trailing) 闭包语法 +* 尾随(Trailing)闭包语法 -### 闭包表达式 (Closure Expressions) +## 闭包表达式(Closure Expressions) --- -嵌套函数 (**这里需要函数章节提供相应链接及锚点进行配合**) 是一个在较复杂函数中方便进行命名和定义自包含代码模块的方式。 +[嵌套函数](../chapter2/06_Function.html#nested_function) 是一个在较复杂函数中方便进行命名和定义自包含代码模块的方式。 当然,有时候撰写小巧的没有完整定义和命名的类函数结构也是很有用处的,尤其是在您处理一些函数并需要将另外一些函数作为该函数的参数时。 闭包表达式是一种利用简洁语法构建内联闭包的方式。 @@ -44,12 +44,12 @@ Swift 的闭包表达式拥有简洁的风格,并鼓励在常见场景中进 每一次迭代都用更简洁的方式描述了相同的功能。 -##### sort 函数 (The Sort Function) +### sort 函数(The Sort Function) Swift 标准库提供了`sort`函数,会根据您提供的基于输出类型排序的闭包函数将已知类型数组中的值进行排序。 一旦排序完成,函数会返回一个与原数组大小相同的新数组,该数组中包含已经正确排序的同类型元素。 -下面的闭包表达式示例使用`sort`函数对一个 **String** 类型的数组进行字母逆序排序,以下是初始数组值: +下面的闭包表达式示例使用`sort`函数对一个`String`类型的数组进行字母逆序排序,以下是初始数组值: ``` let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"] @@ -60,7 +60,7 @@ let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"] * 已知类型的数组 * 闭包函数,该闭包函数需要传入与数组类型相同的两个值,并返回一个布尔类型值来告诉`sort`函数当排序结束后传入的第一个参数排在第二个参数前面还是后面。如果第一个参数值出现在第二个参数值前面,排序闭包函数需要返回`true`,反之返回`false`。 -该例子对一个 **String** 类型的数组进行排序,因此排序闭包函数类型需为`(String, String) -> Bool`。 +该例子对一个`String`类型的数组进行排序,因此排序闭包函数类型需为`(String, String) -> Bool`。 提供排序闭包函数的一种方式是撰写一个符合其类型要求的普通函数,并将其作为`sort`函数的第二个参数传入: @@ -73,7 +73,7 @@ var reversed = sort(names, backwards) ``` 如果第一个字符串 (`s1`) 大于第二个字符串 (`s2`),`backwards`函数返回`true`,表示在新的数组中`s1`应该出现在`s2`前。 -对于字符串中的字符来说,"大于" 表示 "按照字母顺序较晚出现"。 +对于字符串中的字符来说,“大于” 表示 “按照字母顺序较晚出现”。 这意味着字母`"B"`大于字母`"A"`,字符串`"Tom"`大于字符串`"Tim"`。 其将进行字母逆序排序,`"Barry"`将会排在`"Alex"`之后。 @@ -81,7 +81,7 @@ var reversed = sort(names, backwards) 在下面的例子中,利用闭合表达式语法可以更好的构造一个内联排序闭包。 -##### 闭包表达式语法 (Closure Expression Syntax) +### 闭包表达式语法(Closure Expression Syntax) 闭包表达式语法有如下一般形式: @@ -91,7 +91,7 @@ var reversed = sort(names, backwards) } ``` -闭包表达式语法可以使用常量、变量和`inout` (**这里也需要函数章节提供相应链接和锚点进行配合**) 类型作为参数,不提供默认值。 +闭包表达式语法可以使用常量、变量和`inout`类型作为参数,不提供默认值。 也可以在参数列表的最后使用可变参数。 元组也可以作为参数和返回值。 @@ -119,7 +119,7 @@ reversed = sort(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } ) 这说明`sort`函数的整体调用保持不变,一对圆括号仍然包裹住了函数中整个参数集合。而其中一个参数现在变成了内联闭包 (相比于`backwards`版本的代码)。 -##### 根据上下文推断类型 (Inferring Type From Context) +### 根据上下文推断类型(Inferring Type From Context) 因为排序闭包函数是作为`sort`函数的参数进行传入的,Swift可以推断其参数和返回值的类型。 `sort`期望第二个参数是类型为`(String, String) -> Bool`的函数,因此实际上`String`,`String`和`Bool`类型并不需要作为闭包表达式定义中的一部分。 @@ -132,7 +132,7 @@ reversed = sort(names, { s1, s2 in return s1 > s2 } ) 实际上任何情况下,通过内联闭包表达式构造的闭包作为参数传递给函数时,都可以推断出闭包的参数和返回值类型,这意味着您几乎不需要利用完整格式构造任何内联闭包。 -##### 单表达式闭包隐式返回 (Implicit Return From Single-Expression Clossures) +### 单表达式闭包隐式返回(Implicit Return From Single-Expression Clossures) 单行表达式闭包可以通过隐藏`return`关键字来隐式返回单行表达式的结果,如上版本的例子可以改写为: @@ -140,11 +140,11 @@ reversed = sort(names, { s1, s2 in return s1 > s2 } ) reversed = sort(names, { s1, s2 in s1 > s2 } ) ``` -在这个例子中,`sort`函数的第二个参数函数类型明确了闭包必须返回一个 **Bool** 类型值。 -因为闭包函数体只包含了一个单一表达式 (`s1 > s2`),该表达式返回 **Bool** 类型值,因此这里没有歧义,`return`关键字可以省略。 +在这个例子中,`sort`函数的第二个参数函数类型明确了闭包必须返回一个`Bool`类型值。 +因为闭包函数体只包含了一个单一表达式 (`s1 > s2`),该表达式返回`Bool`类型值,因此这里没有歧义,`return`关键字可以省略。 -##### 参数名称缩写 (Shorthand Argument Names) +### 参数名称缩写(Shorthand Argument Names) Swift 自动为内联函数提供了参数名称缩写功能,您可以直接通过`$0`,`$1`,`$2`来顺序调用闭包的参数。 @@ -155,13 +155,13 @@ Swift 自动为内联函数提供了参数名称缩写功能,您可以直接 reversed = sort(names, { $0 > $1 } ) ``` -在这个例子中,`$0`和`$1`表示闭包中第一个和第二个 **String** 类型的参数。 +在这个例子中,`$0`和`$1`表示闭包中第一个和第二个`String`类型的参数。 -##### 运算符函数 (Operator Functions) +### 运算符函数(Operator Functions) 实际上还有一种更简短的方式来撰写上面例子中的闭包表达式。 -Swift 的 **String** 类型定义了关于大于号 (`>`) 的字符串实现,其作为一个函数接受两个 **String** 类型的参数并返回 **Bool** 类型的值。 +Swift 的`String`类型定义了关于大于号 (`>`) 的字符串实现,其作为一个函数接受两个`String`类型的参数并返回`Bool`类型的值。 而这正好与`sort`函数的第二个参数需要的函数类型相符合。 因此,您可以简单地传递一个大于号,Swift可以自动推断出您想使用大于号的字符串函数实现: @@ -169,15 +169,15 @@ Swift 的 **String** 类型定义了关于大于号 (`>`) 的字符串实现, reversed = sort(names, >) ``` -更多关于运算符表达式的内容请查看 [Operator Functions]() (**这里需要 Operator Functions 进行配合**)。 +更多关于运算符表达式的内容请查看 [运算符函数](../chapter2/23_Advanced_Operators.html#operator_functions)。 -### 尾随闭包 (Trailing Closures) +## 尾随闭包(Trailing Closures) --- 如果您需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用尾随闭包来增强函数的可读性。 -尾随闭包是一个书写在函数括号之外(之后)的闭包表达式,函数支持将其作为最后一个参数调用。 +尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。 ``` func someFunctionThatTakesAClosure(closure: () -> ()) { @@ -198,7 +198,7 @@ someFunctionThatTakesAClosure() { ``` > 注意: > 如果函数只需要闭包表达式一个参数,当您使用尾随闭包时,您甚至可以把 () 省略掉。 -NOTE + 在上例中作为`sort`函数参数的字符串排序闭包可以改写为: @@ -207,13 +207,13 @@ reversed = sort(names) { $0 > $1 } ``` 当闭包非常长以至于不能在一行中进行书写时,尾随闭包变得非常有用。 -举例来说,Swift 的 **Array** 类型有一个`map`方法,其获取一个闭包表达式作为其唯一参数。 +举例来说,Swift 的`Array`类型有一个`map`方法,其获取一个闭包表达式作为其唯一参数。 数组中的每一个元素调用一次该闭包函数,并返回该元素所映射的值(也可以是不同类型的值)。 具体的映射方式和返回值类型由闭包来指定。 当提供给数组闭包函数后,`map`方法将返回一个新的数组,数组中包含了与原数组一一对应的映射后的值。 -下例介绍了如何在`map`方法中使用尾随闭包将 **Int** 类型数组`[16,58,510]`转换为包含对应 **String** 类型的数组`["OneSix", "FiveEight", "FiveOneZero"]`: +下例介绍了如何在`map`方法中使用尾随闭包将`Int`类型数组`[16,58,510]`转换为包含对应`String`类型的数组`["OneSix", "FiveEight", "FiveOneZero"]`: ``` let digitNames = [ @@ -246,8 +246,8 @@ let strings = numbers.map { `map`在数组中为每一个元素调用了闭包表达式。 您不需要指定闭包的输入参数`number`的类型,因为可以通过要映射的数组类型进行推断。 -闭包`number`参数被声明为一个变量参数 (变量的具体描述请参看[Constant and Variable Parameters]()(**这里需要Closure Expression Syntax进行配合**)),因此可以在闭包函数体内对其进行修改。 -闭包表达式制定了返回类型为 **String**,以表明存储映射值的新数组类型为 **String**。 +闭包`number`参数被声明为一个变量参数 (变量的具体描述请参看[常量参数和变量参数](../chapter2/06_Functions.html#closure_expression_syntax)),因此可以在闭包函数体内对其进行修改。 +闭包表达式制定了返回类型为`String`,以表明存储映射值的新数组类型为`String`。 闭包表达式在每次被调用的时候创建了一个字符串并返回。 其使用求余运算符 (number % 10) 计算最后一位数字并利用`digitNames`字典获取所映射的字符串。 @@ -269,7 +269,7 @@ let strings = numbers.map { 上例中尾随闭包语法在函数后整洁封装了具体的闭包功能,而不再需要将整个闭包包裹在`map`函数的括号内。 -### 捕获值 (Capturing Values) +## 捕获值(Capturing Values) --- @@ -297,13 +297,13 @@ func makeIncrementor(forIncrement amount: Int) -> () -> Int { `makeIncrementor`返回类型为`() -> Int`。 这意味着其返回的是一个函数,而不是一个简单类型值。 -该函数在每次调用时不接受参数只返回一个 **Int** 类型的值。 -关于函数返回其他函数的内容,请查看[Function Types as Return Types]()(**需要函数章节进行配合**)。 +该函数在每次调用时不接受参数只返回一个`Int`类型的值。 +关于函数返回其他函数的内容,请查看[函数类型作为返回类型](../chapter2/06_Functions.html#function_types_as_return_types)。 `makeIncrementor`函数定义了一个整型变量`runningTotal`(初始为0) 用来存储当前跑步总数。 该值通过`incrementor`返回。 -`makeIncrementor`有一个 **Int** 类型的参数,其外部命名为`forIncrement`, 内部命名为`amount`,表示每次`incrementor`被调用时`runningTotal`将要增加的量。 +`makeIncrementor`有一个`Int`类型的参数,其外部命名为`forIncrement`, 内部命名为`amount`,表示每次`incrementor`被调用时`runningTotal`将要增加的量。 `incrementor`函数用来执行实际的增加操作。 该函数简单地使`runningTotal`增加`amount`,并将其返回。 @@ -359,10 +359,10 @@ incrementByTen() > 注意: > 如果您闭包分配给一个类实例的属性,并且该闭包通过指向该实例或其成员来捕获了该实例,您将创建一个在闭包和实例间的强引用环。 -> Swift 使用捕获列表来打破这种强引用环。更多信息,请参考 [Strong Reference Cycles for Closures]()(**需要ARC章节进行配合**)。 +> Swift 使用捕获列表来打破这种强引用环。更多信息,请参考 [闭包引起的循环强引用](../chapter2/16_Automatic_Reference_Counting.html#strong_reference_cycles_for_closures)。 -### 闭包是引用类型 +## 闭包是引用类型(Closures Are Reference Types) ---