闭包表达式: closure expression
闭包表达式,其形式如下:
{
(参数列表) -> 返回值类型 in
函数体代码
}
通过 in 将函数体代码和(参数列表与返回值类型)区分开来
在swift中,可以通过func定义一个函数,也可以通过闭包表达式定义一个函数
- func的形式
func sum(_ v1: Int, _ v2: Int) -> Int { return v1 + v2 } sum(1, 2) // 3
- 闭包表达式的形式
var fn = { (v1: Int, v2: Int) -> Int in return v1 + v2 } fn(1, 2) // 3
或
{
(v1: Int, v2: Int) -> Int in
return v1 + v2
}(1, 2) // 3
尾随闭包
尾随闭包是一个被书写在函数调用括号后面的闭包表达式
当一个很长的闭包表达式作为函数的最后一个实参时,使用尾随闭包,可以增强函数的可读性
func exec(v1: Int, v2: Int, fn: (Int, Int) -> Int) {
print(fn(v1, v2))
}
// 函数调用
exec(v1: 1, v2: 2) { (v1, v2) -> Int in
return v1 + v2
}
// 可以简写为
exec(v1: 1, v2: 2) {
$0 + $1
}
数组排序
- func的形式:
// true: v1排在v2前面 // false: v1排在v2后面 func cmp(v1: String, v2: String) -> Bool { // 降序:大的排在前面 return v1 > v2 } var arr = ["Kofi", "Abena", "Peter", "Kweku", "Akosua"] arr.sort(by: cmp) print(arr) // 打印结果为 ["Peter", "Kweku", "Kofi", "Akosua", "Abena"]
- 闭包表达式的形式
var arr = ["Kofi", "Abena", "Peter", "Kweku", "Akosua"] arr.sort(by: { (v1: String, v2: String) -> Bool in return v1 > v2 }) arr.sort(by: { v1, v2 in return v1 > v2 }) arr.sort(by: { v1, v2 in v1 > v2 }) arr.sort(by: { $0 > $1 }) arr.sort(by: >) // 尾随闭包 arr.sort() { $0 > $1 } arr.sort { $0 > $1 }
闭包: closure
一个函数和它所捕获的变量\常量组合起来,称为闭包
- 一般指定义在函数内部的函数
- 一般它捕获的是外层函数的局部变量\常量
typealias aClosure = (Int) -> Int func getClosure() -> aClosure { var num = 1 func plus(_ i: Int) -> Int { num += i return num } return plus } // 返回的plus和num构成了闭包 var ac = getClosure() // 下面打印的结果是什么? print(ac(1)) print(ac(2)) print(ac(3))
先看一下print的结果: 2 4 7
- 在getClosure调用之后,得到一个闭包,赋给全局变量ac
- getClosure中定义的局部变量num释放
- 在print函数中,调用ac,对num进行+操作
- 无异常,正常打印
大家有没有好奇,为什么没有抛异常?
我们先对plus函数做如下修改,使其没有捕捉外层函数的num变量
其汇编如下:
我们将其修改回来,断点打在相同的位置,此时的汇编如下:
-
从汇编结果中可以看出,闭包在捕获变量之后,会通过allocObject函数,在堆中开辟出一段空间
-
然后将num中的值拷贝一份到地址为(rax + 0x10)的堆空间中
-
此后对num的操作,都是对堆空间中的值进行的操作
从下图可以看到num的值在堆空间中的具体变化过程
注意
如果返回值是函数类型,那么参数的修饰要保持一致
func add(_ num: Int) -> (inout Int) -> Void {
func plus(v: inout Int) {
v += num
}
return plus;
}
var num = 5
add(20)(&num)
print(num) // 25
自动闭包:@autoclosure
func getFirstPositive(_ v1: Int, _ v2: @autoclosure () -> Int) -> Int {
return v1 > 0 ? v1 : v2()
}
getFirstPositive(10, 20)
- @autoclosure 会自动将 20 封装成闭包 { 20 }
- @autoclosure 只支持 () -> T 格式的参数
- @autoclosure 并非只支持最后一个参数
- 空合并运算符 ?? 使用了 @autoclosure 技术