首页 > 其他 > 详细

闭包表达式和闭包

时间:2021-04-17 20:39:28      阅读:42      评论:0      收藏:0      [点我收藏+]

闭包表达式(Closure Expression)

  • 在Swift中,可以通过func定义一个函数,也可以通过闭包表达式定义一个函数
    技术分享图片
  • 闭包表达式的缩写
    技术分享图片

尾随闭包

  • 如果将一个很长的闭包表达式作为函数的最后一个实参,使用尾随闭包可以增强函数的可读性

    • 尾随闭包是一个呗书写在函数调用括号外面(后面)的闭包表达式
      技术分享图片
  • 如果闭包表达式是函数的唯一实参,而且使用了尾随闭包的语法,那就不需要在函数名后面写圆括号
    技术分享图片

  • 示例:

    • 数组的排序
var arr = [10, 1, 4, 20, 99]
    // 从高到低排序
func cmp(i1: Int, i2: Int) -> Bool {
     return i1 > i2
 }
 arr.sort(by: cmp)
 arr.sort(by: {i1,i2 in i1 > i2})
 arr.sort(by: {$0 > $1})
 arr.sort(by: >)
 arr.sort{ $0 > $1 }

 print(arr)

闭包

  • 一个函数和它所捕获的变量\常量环境组合起来,称为闭包
    • 一般指定义在函数内部的函数
    • 一般它捕获的是外层函数的局部变量\常量
typealias Fn = (Int) -> Int
func getFn() -> Fn {
    // 局部变量
    var num = 0
    func plus(_ i: Int) -> Int {
        num += 1
        return num
    }
    return plus
}// 返回的plus和num形成了闭包

/* 等价于下面额写法
 func getFn() -> Fn {
    var num = 0
    return {
        num += $0
        return num
    }
 }
 */
var fn1 = getFn() //分配了2块不同的堆空间
var fn2 = getFn()
print(fn1(1)) // 1
print(fn2(2)) // 2
print(fn1(3)) // 4
print(fn2(4)) // 6
print(fn1(5)) // 9
print(fn2(6)) // 12

  • 可以把闭包想象成一个类的实例对象
    • 内存在堆空间
    • 捕获的局部变量\常量就是对象的成员(存储属性)
    • 组成闭包的函数就类内部定义的方法
class Closure {
    var num = 0
    func plus(_ i: Int) -> Int {
        num += i
        return num
    }
}
var cs1 = Closure()
var cs2 = Closure()
cs1.plus(1) // 1
cs2.plus(2) // 2
cs1.plus(3) // 4
cs2.plus(4) // 6
cs1.plus(5) // 9
cs2.plus(6) // 12

typealias Fn = (Int) -> Int
var num = 11

func getFn() -> Fn {
    var num = 11
    
    func plus(_ i: Int) -> Int {
        num += 1
        return num
    }
    
    num = 14
    return plus
} // 捕获的变量是 num = 14 如果是全局变量 则不会发生捕获

var fn1 = getFn()
fn1(1)
fn1(2)

var fn2 = getFn()
fn1(3)
fn1(4)

/////////////////////////////
typealias Fn = (Int) -> (Int, Int)

func getFns() -> (Fn, Fn) {
    var num1 = 0 // 捕获的时候 分配了2份堆空间 分别alloc了1次
    var num2 = 0 // alloc 分配的地址是随机的不一定连续
    
    func plus(_ i: Int) -> (Int, Int) {
        num1 += i
        num2 += i << 1
        return (num1, num2)
    }
    
    func minus(_ i: Int) -> (Int, Int) {
        num1 -= i
        num2 -= i << 1
        return (num1, num2)
    }
    return (plus, minus)
}

let (p, m) = getFns() // 只会分配一份堆空间
print(p(6)) //(6, 12)

print(m(5)) //(1, 2)

print(p(4)) //(5, 10)

print(m(3)) //(2 , 4)

for i in 1...3 {
    
//    func myF() -> Int {
//        return i
//    }
//
//    functions.append(myF)
    functions.append{i}
}
for f in functions {
    print(f())
}
//  结果 1 2 3

自动闭包

// 如果第一个数大于0, 返回第一个数否则返回第二个数
func getFirstPositive(_ v1: Int, _ v2: Int) -> Int {
    return v1 > 0 ? v1 : v2
}

getFirstPositive(10, 11) // 有个问题, 无论如何都会传入第二个数,即使第一个数 已经大于0了

// 改版:


func getFirstPositive1(_ v1: Int, _ v2: () -> Int) -> Int {
    return v1 > 0 ? v1 : v2()
}
getFirstPositive1(10) {
    print("test ----")
    return 20
}
getFirstPositive1(10){20}
// 这样 10大于0 就不会调用函数了
// 但是这样调用 在简单数据时候 可读性很差
// 所以推出了 自动闭包 autoclosure
func getFirstPositive2(_ v1: Int, _ v2: @autoclosure () -> Int) -> Int {
    return v1 > 0 ? v1 : v2()
}
getFirstPositive2(10, 20)

  • @autoclosure会自动将20 分装成闭包表达式 {20}
  • @autoclosure 只支持 () -> T格式的参数
  • @autoclosure并非只支持最后一个参数
  • 空和运算符 ?? 使用了 @autoclosure技术 public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T
  • @autoclosure 修饰的 值可能会延时执行

闭包表达式和闭包

原文:https://www.cnblogs.com/yilmios/p/14671811.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!