美文网首页
Swift5.1学习随笔之闭包Closure

Swift5.1学习随笔之闭包Closure

作者: SAW_ | 来源:发表于2020-04-16 17:05 被阅读0次

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

    闭包定义:
    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

          本文链接:https://www.haomeiwen.com/subject/xpcdvhtx.html