美文网首页
swift基础——闭包

swift基础——闭包

作者: 李永开 | 来源:发表于2023-02-14 15:56 被阅读0次

    一. 闭包简介

    • 一个函数和它所捕获的变量/常量环境组合起来,成为闭包
    • 如果闭包捕获了局部变量,那么会将该局部变量保存到堆空间
    • 闭包和类非常相似,捕获的局部变量在堆空间,前16个字节储存基本信息

    二. 测试一下

    普通闭包

    //正常函数
    func funcAdd (_ a: Int, _ b: Int) -> Int{
        a + b
    }
    
    //闭包表达式
    var closure = {
        (a : Int, b : Int) -> Int in
        return a + b
    }
    
    //匿名闭包
    //{
    //    (a : Int, b : Int) -> Int in
    //    return a + b
    //}(10, 20)
    
    
    funcAdd(1, 5)
    closure(1, 5)
    

    尾随闭包

    //尾随闭包是一个被书写在函数调用括号外面的闭包表达式,使用尾随闭包增强函数的可读性
    func exe(a: Int, b: Int, closure:(Int, Int)->Int) {
        print(closure(a, b))
    }
    exe(a:100, b:1, closure:{a, b -> Int in return a + b})  //原始
    exe(a:100, b:1, closure:{a, b -> Int in a + b})         //简化,去掉return
    exe(a:100, b:1, closure:{$0 + $1})                      //简化,去掉a,b
    exe(a:100, b:1, closure:+)                              //简化,直接用+
    
    //使用尾随闭包, 就是将最后一个闭包在参数项后面展开
    exe(a:100, b:1) {
        $0+$1
    }
    
    //如果闭包是函数的唯一实参,而且使用了尾随闭包的方式,那么可以简写
    func exeSimple(closure:(Int, Int)->Int) {
        print(closure(1, 2))
    }
    exeSimple(closure: {a, b -> Int in return a + b})
    exeSimple(){
        $0 + $1
    }
    exeSimple{$0 + $1}
    
    //测试demo
    var arr = [1, 3, 8, 2, 7, 6]
    print(arr.sorted())
    //print(arr.sorted(by: <#T##(Int, Int) throws -> Bool#>))
    print(arr.sorted{$0 > $1})
    

    闭包对参数的引用

    //----------------------------- 1-------------------------------
    func retClosure() -> (Int)->Int {
        var num = 100
        
        func innerClo(_ a: Int) -> Int {
            num += a
            return num
        }
        return innerClo
    }
    retClosure()(1) //101
    retClosure()(2) //102
    retClosure()(3) //103
    //num并没有累加
    
    //----------------------------- 2-------------------------------
    //换一种调用方式,num累加了,说明它捕获了num,并且一直再使用这个num
    typealias fn = (Int)->Int
    var fff = retClosure()
    fff(1)         //101
    fff(2)         //103
    fff(3)         //106
    
    
    //----------------------------- 3-------------------------------
    var num = 100
    func retClosureOut() -> (Int)->Int {
        
        func innerClo(_ a: Int) -> Int {
            num += a
            return num
        }
        return innerClo
    }
    retClosureOut()(1) //101
    retClosureOut()(2) //103
    retClosureOut()(3) //106
    //把num放到了外面,num累加
    
    
    
    //----------------------------- 4-------------------------------
    func retClosureChangeNum() -> (Int)->Int {
        var num = 100
        
        func innerClo(_ a: Int) -> Int {
            num += a
            return num
        }
        
        num = 200
        return innerClo
    }
    retClosureChangeNum()(1) //201   很神奇,闭包捕获变量是在return 之前. 所以第一个100被200替换了
    
    
    
    //----------------------------- 5-------------------------------
    typealias retfn = (Int)->Int
    
    func moreClosure() ->(retfn, retfn) {
        var num1 = 0
        
        func add(_ a: Int) -> (Int) {
            num1 += a
            return num1
        }
        
        func sub(_ a: Int) -> (Int) {
            num1 -= a
            return num1
        }
        
        return (add, sub)
    }
    let (add, sub) = moreClosure()
    add(10)         //10
    sub(3)          //7
    add(10000)      //10007
    // 当两个闭包同时引用一个局部变量时,不会创建两个堆空间来保存该变量,而是共用一个变量
    // 闭包捕获的局部变量在堆空间,前16个字节储存基本信息
    

    自动闭包

    
    //: # 自动闭包
    //: * @autoclosure 主要是用来优化性能的,避免多余的计算之类,有可能会延迟调用
    //: * @autoclosure只支持无参的闭包表达式,而且必须有返回值,局限性比较大
    //: * @autoclosure支持重载
    
    总的来说:自动闭包就是把普通值包装成闭包,可以在函数内部决定闭包调用时机(鸡肋🐔)
    
    //@autoclosure
    func getFirstNum1(_ a: Int, _ b: Int) -> Int {
        a > 0 ? a : b
    }
    func getFirstNum2(_ a: Int, _ b: ()->Int) {
        a > 0 ? a : b()
        print(a)
    }
    getFirstNum2(10,{() -> Int in return 20})//10大于0了,期望不执行后面的闭包,所以就有了可以延迟调用的闭包(自动闭包)
    getFirstNum2(10,{20})
    getFirstNum2(10){20}
    
    //加上@autoclosure自动闭包,可以不写{}了  -> 编译器特性,自动加了{}
    func getFirstNum3(_ a: Int, _ b: @autoclosure ()->Int) {
        a > 0 ? a : b()
        print(a)
    }
    getFirstNum3(10,20)
    
    
    let getNumFor4 = {()->Int in
        let a = 100
        let b = 200
        print("这行会走吗?")
        return a + b
    }
    func getFirstNum4(_ a: Int, _ b: @autoclosure ()->Int) {
        a > 0 ? a : b()
        print(a)
    }
    getFirstNum4(10, getNumFor4()) //加了@autoclosure后,编译器发现10 > 0, 所以就不会调用getNumFor4这个闭包表达式,节省了性能(延迟执行)
    getFirstNum4(-10, getNumFor4()) //会打印
    
    
    // ?? 就是基于自动闭包实现的, 下面就是他的实现
    //public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T?) rethrows -> T?
    

    相关文章

      网友评论

          本文标题:swift基础——闭包

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