Swift5.1学习随笔之闭包Closure

闭包闭包表达式不是一个东西

闭包定义:
1、一个函数和它所捕获的变量、常量环境组合起来,称之为闭包

  • 一般指定义在函数内部的函数
  • 一般它捕获的是外层函数的局部变量、常量
func fn() -> () -> () {
    var a = 10
    func fn1() {
        a = 11
    }
    return fn1
}

例子

typealias Fn = (Int) -> Int
func getFn() -> Fn {
    var num = 0
    func plus(_ i: Int) -> Int {
        num += 1
        return num
    }
    return plus
} // 返回的plus和num形成了闭包

var fn = getFn()
print(fn(1)) //1
print(fn(2)) //3
print(fn(3)) //6
print(fn(4)) //10

num是函数局部变量,正常来说调用getFn之后分配一段连续的栈空间,空间内部有8个字节用来存储num变量0
一旦return返回之后意味着函数调用结束,栈空间会被回收,num变量会被销毁,既然栈空间被回收,为何能调用fn

全局变量fn内部持有函数plus的地址信息。
plus持有了局部变量num,根据汇编代码来看,getFn函数内部调用了swift_allocObject,申请了一块堆空间给变量num,使得不会因为函数调用之后被销毁。

可以将闭包想象成一个类的实例对象

  • 内存在堆空间
  • 捕获的局部变量、常量就是对象的成员(存储属性)
  • 组成闭包的函数就是类内部定义的方法
class Closure {
    var num = 0
    func plus(_ i: Int) -> Int {
        num += i
        return num
    }
}
var cs1 = Closure()
print(cs1.plus(1)) //1
print(cs1.plus(2)) //3
print(cs1.plus(3)) //6

如果返回值是函数类型,那么参数的修饰要保持统一

func add(_ num: Int) -> (inout Int) -> Void {
    func plus(v: inout Int) {
        v += num
    }
    return plus
}
var num = 5
add(20)(&num)
print(num)

自动闭包

看个例子

//如果第1个数大于0,返回第1个数,否则返回第2个数
func getFirstPositive(_ v1: Int, _ v2: Int) -> Int {
    return v1 > 0 ? v1 : v2
}
getFirstPositive(10, 20) // 10
getFirstPositive(-2, 20) // 20
getFirstPositive(0, -4) // -4
func getNumber() -> Int {
    let a = 10
    let b = 11
    print("test-----")
    return a + b
}
//返回第1个参数,同时调用了第2个参数的函数实现,输出print("test-----")
getFirstPositive(10, getNumber()) //10

上面函数调用中,第1个参数10大于0,所以返回10,那么第2个参数getNumber()的调用就没必要,浪费资源,如何优化?

//将v2变成一个函数
func getFirstPositive(_ v1: Int, _ v2: () -> Int) -> Int {
    return v1 > 0 ? v1 : v2()
}

getFirstPositive(-10) {
    let a = 10
    let b = 11
    print("test-----111")
    return a + b
} //第1个参数小于0,返回第2个参数,调用了print("test-----111")

getFirstPositive(10) {
    let a = 10
    let b = 11
    print("test-----222")
    return a + b
} //第1个参数大于0,返回第1个参数,没有输出print("test-----111"),说明第2参数没调用

上面的例子中,如果代码比较精简的话,可读性不高:

getFirstPositive1(10, {20})
getFirstPositive1(10) {20}

Swift提供了一个语法:自动闭包
添加关键词:@autoclosure

func getFirstPositive(_ v1: Int, _ v2: @autoclosure () -> Int) -> Int {
    return v1 > 0 ? v1 : v2()
}
getFirstPositive(10, 20)

注意点
1、@autoclosure会自动将20封装成闭包{ 20 }
2、@autoclosure只支持 () -> T 格式的参数
3、@autoclosure并非只支持最后1个参数

func getFirstPositive3(_ v1: Int, _ v2: @autoclosure () -> Int,  _ v3: Int,  _ v4: Int) -> Int {
    return v1 > 0 ? v1 : v2()
}
getFirstPositive3(10, 20, 30, 40)

4、空合并运算符??使用了@autoclosure技术
5、有@autoclosure、无@autoclosure构成了函数重载

func getFirstPositive(_ v1: Int, _ v2: () -> Int) -> Int {
    return v1 > 0 ? v1 : v2()
}

func getFirstPositive(_ v1: Int, _ v2: @autoclosure () -> Int) -> Int {
    return v1 > 0 ? v1 : v2()
}

getFirstPositive(10, 20) //调用 @autoclosure 的getFirstPositive
getFirstPositive(10, {30}) //调动无 @autoclosure 的getFirstPositive

6、为了避免与期望冲突,使用了@autoclosure的地方最好明确注释清楚:这个值会被推迟执行

你可能感兴趣的:(Swift5.1学习随笔之闭包Closure)