Swift闭包:深入理解与应用
立即解锁
发布时间: 2025-08-16 02:35:57 阅读量: 22 订阅数: 30 AIGC 


Swift编程入门与实践指南
# Swift闭包:深入理解与应用
## 1. 闭包概述
闭包是自包含的功能代码块,可以在代码中传递和使用。在Swift中,闭包类似于C和Objective - C中的块,以及其他编程语言中的lambda表达式。闭包可以捕获并存储其定义上下文中的常量和变量的引用,这被称为捕获这些常量和变量,而Swift会自动处理捕获过程中的内存管理。
闭包有三种形式:
- **全局函数**:有名称且不捕获任何值的闭包。
- **嵌套函数**:有名称且可以从其封闭函数中捕获值的闭包。
- **闭包表达式**:以轻量级语法编写的无名闭包,可以从其周围上下文捕获值。
Swift的闭包表达式具有简洁明了的风格,并且有一些优化,鼓励在常见场景中使用简洁、无冗余的语法,这些优化包括:
- 从上下文推断参数和返回值类型
- 单表达式闭包的隐式返回
- 速记参数名称
- 尾随闭包语法
## 2. 闭包表达式示例:sorted(by:)方法
### 2.1 sorted(by:)方法介绍
Swift标准库提供了`sorted(by:)`方法,用于根据你提供的排序闭包对已知类型的数组进行排序。排序完成后,该方法返回一个与原数组类型和大小相同的新数组,其中元素按正确的排序顺序排列,原数组不会被修改。
以下是一个对字符串数组进行反向字母顺序排序的示例:
```swift
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
```
`sorted(by:)`方法接受一个闭包,该闭包接受两个与数组元素类型相同的参数,并返回一个布尔值,用于指示第一个值在排序后应该出现在第二个值之前还是之后。如果第一个值应该出现在第二个值之前,排序闭包应返回`true`,否则返回`false`。
### 2.2 传统函数方式
可以编写一个符合要求的普通函数,并将其作为参数传递给`sorted(by:)`方法:
```swift
func backward(_ s1: String, _ s2: String) -> Bool {
return s1 > s2
}
var reversedNames = names.sorted(by: backward)
// reversedNames is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
```
如果第一个字符串`s1`大于第二个字符串`s2`,`backward(_:_:)`函数将返回`true`,表示`s1`应在排序数组中出现在`s2`之前。
### 2.3 闭包表达式语法
闭包表达式语法的一般形式如下:
```swift
{ ( parameters ) -> return type in
statements
}
```
参数可以是输入输出参数,但不能有默认值。如果命名了可变参数,则可以使用可变参数。元组也可以用作参数类型和返回类型。
以下是上述`backward(_:_:)`函数的闭包表达式版本:
```swift
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
})
```
也可以将其写在一行上:
```swift
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } )
```
### 2.4 从上下文推断类型
由于排序闭包作为参数传递给方法,Swift可以推断其参数类型和返回值类型。因此,`(String, String)`和`Bool`类型不需要在闭包表达式定义中写出,返回箭头`->`和参数名称周围的括号也可以省略:
```swift
reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )
```
### 2.5 单表达式闭包的隐式返回
单表达式闭包可以通过省略`return`关键字来隐式返回其单个表达式的结果:
```swift
reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
```
### 2.6 速记参数名称
Swift会自动为内联闭包提供速记参数名称,如`$0`、`$1`、`$2`等。使用速记参数名称时,可以省略闭包的参数列表,`in`关键字也可以省略:
```swift
reversedNames = names.sorted(by: { $0 > $1 } )
```
### 2.7 运算符方法
Swift的`String`类型将大于运算符`>`定义为一个方法,该方法接受两个`String`类型的参数并返回一个`Bool`值,这与`sorted(by:)`方法所需的方法类型完全匹配。因此,可以直接传递大于运算符:
```swift
reversedNames = names.sorted(by: >)
```
## 3. 尾随闭包
如果需要将一个闭包表达式作为函数的最后一个参数传递,并且闭包表达式很长,那么将其写成尾随闭包会很有用。尾随闭包写在函数调用的括号之后,尽管它仍然是函数的一个参数。使用尾随闭包语法时,在函数调用中不需要写出第一个闭包的参数标签。
以下是一个示例函数:
```swift
func someFunctionThatTakesAClosure(closure: () -> Void) {
// function body goes here
}
```
不使用尾随闭包调用该函数:
```swift
someFunctionThatTakesAClosure(closure: {
// closure's body goes here
})
```
使用尾随闭包调用该函数:
```swift
someFunctionThatTakesAClosure() {
// trailing closure's body goes here
}
```
对于字符串排序的例子,也可以使用尾随闭包:
```swift
reversedNames = names.sorted() { $0 > $1 }
```
如果闭包表达式是函数或方法的唯一参数,并且使用尾随闭包语法,则在调用函数时不需要写出函数或方法名称后面的括号:
```swift
reversedNames = names.sorted { $0 > $1 }
```
### 3.1 尾随闭包在map(_:)方法中的应用
Swift的`Array`类型有一个`map(_:)`方法,它接受一个闭包表达式作为其唯一参数。该闭包会对数组中的每个元素调用一次,并为该元素返回一个替代的映射值(可能是其他类型)。
以下是使用`map(_:)`方法和尾随闭包将整数数组转换为字符串数组的示例:
```swift
let digitNames = [
0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]
let strings = numbers.map { (number) -> String in
var number = number
var output = ""
repeat {
output = digitNames[number % 10]! +
```
0
0
复制全文
相关推荐










