2
2
3
3
将执行的代码组合在一起,而不需要创建命名函数。
4
4
5
- * 闭包 * 是可以在你的代码中传递和使用的独立功能块。Swift 中的闭包类似于其他编程语言中的匿名函数、lambda 表达式和代码块。
5
+ ** 闭包 * * 是可以在你的代码中传递和使用的独立功能块。Swift 中的闭包类似于其他编程语言中的匿名函数、lambda 表达式和代码块。
6
6
7
- 闭包可以捕获和存储其所在上下文中任意常量和变量的引用。这个过程可以看作是将这些常量和变量 * 包含 * 在闭包的作用域内。 Swift 会为你管理在捕获过程中涉及到的所有内存操作。
7
+ 闭包可以捕获和存储其所在上下文中任意常量和变量的引用。这个过程可以看作是将这些常量和变量 ** 包含 * * 在闭包的作用域内。 Swift 会为你管理在捕获过程中涉及到的所有内存操作。
8
8
9
9
> 注意: 如果你不熟悉捕获(capturing)这个概念也不用担心。
10
10
> 在 < doc:Closures#Capturing-Values > 章节有它更详细的介绍。
@@ -26,7 +26,7 @@ Swift 中的闭包表达式风格简洁明了,通过一系列优化,使得
26
26
27
27
在 < doc:Functions#Nested-Functions > 中介绍的嵌套函数,提供了一种便捷的方式,可以在较大的函数内部命名和定义自包含的代码块。然而,有时我们需要更简洁的函数式结构,而不必完整地声明函数名称。这在处理那些接受函数作为参数的函数或方法时特别有用。
28
28
29
- * 闭包表达式* 是一种以简短、集中的语法编写内联闭包的方法。在保证不丢失它语法清晰和意图的同时,闭包表达式提供了几种优化的语法简写形式。下面的闭包表达式通过对 ` sorted(by:) ` 这一示例的多次迭代来展示这个过程,每次迭代都使用了更加简洁的方式描述了相同功能。
29
+ ** 闭包表达式* * 是一种以简短、集中的语法编写内联闭包的方法。在保证不丢失它语法清晰和意图的同时,闭包表达式提供了几种优化的语法简写形式。下面的闭包表达式通过对 ` sorted(by:) ` 这一示例的多次迭代来展示这个过程,每次迭代都使用了更加简洁的方式描述了相同功能。
30
30
31
31
### Sorted 方法
32
32
@@ -46,7 +46,7 @@ let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
46
46
```
47
47
-->
48
48
49
- ` sorted(by:) ` 方法接受一个闭包,该闭包函数需要传入与数组元素类型相同的两个值,并返回一个布尔类型值,来表明排序后第一个参数排在第二个参数前面还是后面。如果第一个参数值出现在第二个参数值 * 前面 * ,排序闭包函数需要返回 ` true ` ,反之返回 ` false ` 。
49
+ ` sorted(by:) ` 方法接受一个闭包,该闭包函数需要传入与数组元素类型相同的两个值,并返回一个布尔类型值,来表明排序后第一个参数排在第二个参数前面还是后面。如果第一个参数值出现在第二个参数值 ** 前面 * * ,排序闭包函数需要返回 ` true ` ,反之返回 ` false ` 。
50
50
51
51
该例子对一个 ` String ` 类型的数组进行排序,因此排序闭包函数类型需为 ` (String, String) -> Bool ` 。
52
52
@@ -87,7 +87,7 @@ var reversedNames = names.sorted(by: backward)
87
87
}
88
88
```
89
89
90
- 闭包表达式语法中的 * 参数 * 可以是 in-out 参数,但不能具有默认值。如果你命名了可变参数,也可以使用可变参数。元组也可以用作参数类型和返回类型。
90
+ 闭包表达式语法中的 ** 参数 * * 可以是 in-out 参数,但不能具有默认值。如果你命名了可变参数,也可以使用可变参数。元组也可以用作参数类型和返回类型。
91
91
92
92
下面的示例展示了上面的 ` backward(_:_:) ` 函数对应的闭包表达式版本:
93
93
@@ -108,7 +108,7 @@ reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
108
108
```
109
109
-->
110
110
111
- 需要注意的是,内联闭包的参数和返回类型的声明与 ` backward(_:_:) ` 函数的声明相同。在这两种情况下,它都写为 ` (s1: String, s2: String) -> Bool ` 。但是在内联闭包表达式中,参数和返回类型都写入 * 大括号* 内,而不是大括号外。
111
+ 需要注意的是,内联闭包的参数和返回类型的声明与 ` backward(_:_:) ` 函数的声明相同。在这两种情况下,它都写为 ` (s1: String, s2: String) -> Bool ` 。但是在内联闭包表达式中,参数和返回类型都写入 ** 大括号* * 内,而不是大括号外。
112
112
113
113
闭包函数主体的开始以 ` in ` 关键字开始。这个关键字表示闭包的参数和返回类型定义已经结束,接下来是闭包的实际内容。
114
114
@@ -207,7 +207,7 @@ reversedNames = names.sorted(by: { $0 > $1 } )
207
207
208
208
### 运算符方法
209
209
210
- 实际上有一种 * 更短的 * 方法来编写上面的闭包表达式 。Swift 的 ` String ` 类型定义了关于大于运算符 ( ` > ` ) 的字符串实现方法,该方法具有两个 ` String ` 类型的参数,并返回一个 ` Bool ` 类型的值。这正好符合 ` sorted(by:) ` 方法所需的函数类型。因此,你可以直接传入大于运算符,Swift 会推断出你想使用它的字符串特定实现:
210
+ 实际上有一种 ** 更短 ** 的方法来编写上面的闭包表达式 。Swift 的 ` String ` 类型定义了关于大于运算符 ( ` > ` ) 的字符串实现方法,该方法具有两个 ` String ` 类型的参数,并返回一个 ` Bool ` 类型的值。这正好符合 ` sorted(by:) ` 方法所需的函数类型。因此,你可以直接传入大于运算符,Swift 会推断出你想使用它的字符串特定实现:
211
211
212
212
``` swift
213
213
reversedNames = names.sorted (by : > )
@@ -226,7 +226,7 @@ reversedNames = names.sorted(by: >)
226
226
227
227
## 尾随闭包
228
228
229
- 如果你需要将闭包表达式作为函数的最后一个参数传递给函数,并且闭包表达式很长,则将其编写为 * 尾随闭包* 的形式可能会很有用。在函数调用的括号后编写一个尾随闭包,该尾随闭包仍然会作为该函数的一个参数。使用尾随闭包语法时,不用在函数调用过程中为第一个闭包声明参数名。函数调用可以包含多个尾随闭包;但是,下面的前几个示例只使用了单个尾随闭包。
229
+ 如果你需要将闭包表达式作为函数的最后一个参数传递给函数,并且闭包表达式很长,则将其编写为 ** 尾随闭包* * 的形式可能会很有用。在函数调用的括号后编写一个尾随闭包,该尾随闭包仍然会作为该函数的一个参数。使用尾随闭包语法时,不用在函数调用过程中为第一个闭包声明参数名。函数调用可以包含多个尾随闭包;但是,下面的前几个示例只使用了单个尾随闭包。
230
230
231
231
``` swift
232
232
func someFunctionThatTakesAClosure (closure : () -> Void ) {
@@ -369,7 +369,7 @@ let strings = numbers.map { (number) -> String in
369
369
370
370
闭包表达式每次调用时都会生成一个名为 ` output ` 的字符串。它使用求余运算符 ( ` number % 10 ` ) 计算 ` number ` 的最后一位数字,并使用此数字在 ` digitNames ` 字典中查找所映射的字符串。这个闭包可用于创建任何一个大于零的整数的字符串表示形式。
371
371
372
- > 注意: 对 ` digitNames ` 字典的下标访问后面跟着一个感叹号( ` ! ` )。这是因为字典的下标返回一个可选值,表示如果键不存在,字典查找可能会失败。在上面的例子中,我们可以保证 number % 10 总是 digitNames 字典的有效键,所以使用感叹号来强制解包下标返回的可选 ` String ` 值。
372
+ > 注意: 对 ` digitNames ` 字典的下标访问后面跟着一个感叹号( ` ! ` )。这是因为字典的下标返回一个可选值,表示如果键不存在,字典查找可能会失败。在上面的例子中,我们可以保证 number % 10 总是 digitNames 字典的有效键,所以使用感叹号来强制解包下标返回的可选 ` String ` 值。
373
373
374
374
从 ` digitNames ` 字典中获取的字符串会被添加到 ` output ` 的开头,这样就巧妙地实现了数字的反向字符串构建。(例如,` number % 10 ` 的计算结果:对于 ` 16 ` 得到 ` 6 ` ,对于 ` 58 ` 得到 ` 8 ` ,对于 ` 510 ` 得到 ` 0 ` 。)
375
375
@@ -441,11 +441,11 @@ loadPicture(from: someServer) { picture in
441
441
442
442
在此示例中,` loadPicture(from:completion:onFailure:) ` 函数将其网络任务分配到后台,并在网络任务完成时调用两个完成处理程序之一。通过这种方法编写函数,可以清楚地将负责处理网络故障的代码与在成功下载后更新用户界面的代码分开,而不是只使用一个闭包处理两种情况。
443
443
444
- > 注意: (完成处理)Completion handlers 可能会变得难以阅读,特别是当你需要嵌套多个处理时。一种替代方法是使用异步代码,详情请参阅 < doc:Concurrency > 章节。
444
+ > 注意: (完成处理)Completion handlers 可能会变得难以阅读,特别是当你需要嵌套多个处理时。一种替代方法是使用异步代码,详情请参阅 < doc:Concurrency > 章节。
445
445
446
446
## 值捕获
447
447
448
- 闭包可以从定义它的环境上下文中 * 捕获 * 常量和变量。即使定义这些常量和变量的原作用域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。
448
+ 闭包可以从定义它的环境上下文中 ** 捕获 * * 常量和变量。即使定义这些常量和变量的原作用域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。
449
449
450
450
在 Swift 中,可以捕获值的最简单的闭包形式是嵌套函数,它编写在另一个函数体中。嵌套函数可以捕获其外部函数的任何参数,也可以捕获在外部函数中定义的任何常量和变量。
451
451
@@ -477,7 +477,7 @@ func makeIncrementer(forIncrement amount: Int) -> () -> Int {
477
477
```
478
478
-->
479
479
480
- ` makeIncrementer ` 的返回类型为 ` () -> Int ` 。这意味着它返回一个 * 函数 * ,而不是一个简单的值。它返回的函数没有参数,每次调用它时都返回一个 ` Int ` 值。要了解函数如何返回其他函数,请参阅 < doc:Functions#Function-Types-as-Return-Types > 。
480
+ ` makeIncrementer ` 的返回类型为 ` () -> Int ` 。这意味着它返回一个 ** 函数 * * ,而不是一个简单的值。它返回的函数没有参数,每次调用它时都返回一个 ` Int ` 值。要了解函数如何返回其他函数,请参阅 < doc:Functions#Function-Types-as-Return-Types > 。
481
481
482
482
` makeIncrementer(forIncrement:) ` 函数定义了一个名为 ` runningTotal ` 的整数变量,用于存储即将返回的增量器的当前累计总和。这个变量初始化为 ` 0 ` 。
483
483
@@ -507,7 +507,7 @@ func incrementer() -> Int {
507
507
508
508
` incrementer() ` 函数没有任何参数,但它在函数体内引用了 ` runningTotal ` 和 ` amount ` 。这是通过捕获外围函数中 ` runningTotal ` 和 ` amoun ` t 的 引用 来实现的,并在自己的函数体中使用这些引用。通过引用捕获可以确保当 ` makeIncrementer ` 函数调用结束时,` runningTotal ` 和 ` amount ` 不会消失。同时,这也保证了在下次调用 ` incrementer ` 函数时,` runningTotal ` 仍然可用。
509
509
510
- > 注意: 作为一项优化,如果值不会被闭包改变,并且该值在创建闭包后不会改变,那么 Swift 可能会捕获并存储该值的 * 副本 * 。
510
+ > 注意: 作为一项优化,如果值不会被闭包改变,并且该值在创建闭包后不会改变,那么 Swift 可能会捕获并存储该值的 ** 副本 * * 。
511
511
>
512
512
> Swift 也会负责被捕获变量涉及的所有内存管理工作,包括释放不再需要的变量。
513
513
@@ -598,13 +598,13 @@ incrementByTen()
598
598
```
599
599
-->
600
600
601
- > 注意: 如果将闭包赋值给类实例的属性,并且闭包通过引用实例或其成员来捕获该实例,则将在闭包和实例之间创建一个强循环引用。Swift 使用 * 捕获列表* 来打破这些强循环引用。有关更多信息,请参阅 < doc:AutomaticReferenceCounting#Strong-Reference-Cycles-for-Closures > .
601
+ > 注意: 如果将闭包赋值给类实例的属性,并且闭包通过引用实例或其成员来捕获该实例,则将在闭包和实例之间创建一个强循环引用。Swift 使用 ** 捕获列表* * 来打破这些强循环引用。有关更多信息,请参阅 < doc:AutomaticReferenceCounting#Strong-Reference-Cycles-for-Closures > .
602
602
603
603
## 闭包是引用类型
604
604
605
- 在上面的示例中,` incrementBySeven ` 和 ` incrementByTen ` 是常量,但这些常量引用的闭包仍然能够递增它们捕获的 ` runningTotal ` 变量。这是因为函数和闭包是 * 引用类型* 。
605
+ 在上面的示例中,` incrementBySeven ` 和 ` incrementByTen ` 是常量,但这些常量引用的闭包仍然能够递增它们捕获的 ` runningTotal ` 变量。这是因为函数和闭包是 ** 引用类型* * 。
606
606
607
- 每当你将函数或闭包赋值给一个常量或变量时,你实际上是在将该常量或变量设置为对函数或闭包的 * 引用* 。在上面的示例中,` incrementByTen ` * 引用 * 的闭包选择是常量,而不是闭包本身的内容。
607
+ 每当你将函数或闭包赋值给一个常量或变量时,你实际上是在将该常量或变量设置为对函数或闭包的 ** 引用** 。在上面的示例中,` incrementByTen ` ** 引用 * * 的闭包选择是常量,而不是闭包本身的内容。
608
608
609
609
这也意味着,如果将闭包分配给两个不同的常量或变量,则这两个常量或变量都引用同一闭包。
610
610
@@ -638,7 +638,7 @@ incrementByTen()
638
638
639
639
## 逃逸闭包
640
640
641
- 当闭包作为参数传递给函数,但是这个闭包在函数返回之后才被执行,该闭包被称为 * 逃逸 * 函数。当你声明一个将闭包作为其参数之一的函数时,你可以在参数的类型之前写入 ` @escaping ` ,以表示这个闭包是允许逃逸的。
641
+ 当闭包作为参数传递给函数,但是这个闭包在函数返回之后才被执行,该闭包被称为 ** 逃逸 * * 函数。当你声明一个将闭包作为其参数之一的函数时,你可以在参数的类型之前写入 ` @escaping ` ,以表示这个闭包是允许逃逸的。
642
642
643
643
当一个闭包作为参数传递给一个函数,但在函数返回后才被调用时,我们称这个闭包从函数中 逃逸。当你声明一个接受闭包作为参数的函数时,你可以在参数类型前标注 ` @escaping ` ,以表明这个闭包允许逃逸。
644
644
@@ -835,9 +835,9 @@ struct SomeStruct {
835
835
836
836
## 自动闭包
837
837
838
- * 自动闭包* 是一种自动创建的闭包,用于包装作为参数传递给函数的表达式。它不接受任何参数,当它被调用时,它返回包裹在其内部的表达式的值。这种便利语法让你能够省略闭包的大括号,用一个普通的表达式来代替显式的闭包。
838
+ ** 自动闭包* * 是一种自动创建的闭包,用于包装作为参数传递给函数的表达式。它不接受任何参数,当它被调用时,它返回包裹在其内部的表达式的值。这种便利语法让你能够省略闭包的大括号,用一个普通的表达式来代替显式的闭包。
839
839
840
- 我们经常会 * 调用* 采用自动闭包的函数,但是很少去 * 实现 * 这样的函数。例如,` assert(condition:message:file:line:) ` 函数接受自动闭包作为它的 ` condition ` 和 ` message ` 参数; 其 ` condition ` 参数仅在 Debug 版本中计算,而其 ` message ` 参数仅在 ` condition ` 为 ` false ` 时计算。
840
+ 我们经常会 ** 调用** 采用自动闭包的函数,但是很少去 ** 实现 * * 这样的函数。例如,` assert(condition:message:file:line:) ` 函数接受自动闭包作为它的 ` condition ` 和 ` message ` 参数; 其 ` condition ` 参数仅在 Debug 版本中计算,而其 ` message ` 参数仅在 ` condition ` 为 ` false ` 时计算。
841
841
842
842
自动闭包允许您延迟计算,因为在你调用这个闭包之前,内部代码不会运行。延迟计算对于有副作用或高计算成本的代码非常有用,因为它使得你能控制代码的执行时机。下面的代码展示了闭包如何延时计算。
843
843
@@ -943,7 +943,7 @@ serve(customer: customersInLine.remove(at: 0))
943
943
```
944
944
-->
945
945
946
- > 注意: 过度使用自动闭包可能会使您的代码难以理解。上下文和函数名称应明确表示计算正在被推迟。
946
+ > 注意: 过度使用自动闭包可能会使您的代码难以理解。上下文和函数名称应明确表示计算正在被推迟。
947
947
948
948
如果您想要允许一个自动闭包可以逃逸,请同时使用 ` @autoclosure ` 和 ` @escaping ` 属性。` @escaping ` 属性在上面的 < doc:Closures#Escaping-Closures > 中进行了描述。
949
949
0 commit comments