📜  Swift-闭包(1)

📅  最后修改于: 2023-12-03 15:35:12.875000             🧑  作者: Mango

Swift 闭包

在 Swift 中,闭包是一种特殊的函数类型,可以捕获和存储引用任何常量和变量值的通用代码块。闭包类似于 Objective-C 中的代码块 (blocks) 或者 C 语言中的函数指针,但是更加灵活和强大。

语法

Swift 中的闭包语法很简洁:

{ (parameters) -> return type in
    statements
}

其中,

  • parameters 是一个逗号分隔的参数列表,可以为空;
  • return type 是返回值的类型,可以省略;
  • in 将参数列表与闭包的函数体分离开。

例如,一个简单的闭包可以这样写:

let hello = { print("Hello, world!") }
hello() // Hello, world!

这个闭包不需要任何参数,没有返回值,也没有使用任何外部变量。

捕获值

闭包可以从周围的上下文中捕获常量或者变量的引用,即使这些常量或者变量在闭包定义时并不在同一个作用域内。捕获的值会在闭包内被存储,这些值在闭包代码块中可以被引用和修改。

例如,在下面的代码中,greetingMaker 是一个自由变量,闭包表达式携带了一个指向这个变量的引用:

func makeGreetingMaker() -> (() -> String) {
    var name = "world"
    let greetingMaker = { "Hello, \(name)!" }
    return greetingMaker
}

let hello = makeGreetingMaker()
print(hello()) // Hello, world!

name = "Swift"
print(hello()) // Hello, Swift!
尾随闭包

Swift 中的函数调用可以使用尾随闭包简化语法。如果一个闭包是函数的最后一个参数,并且闭包表达式非常长,可以使用尾随闭包将闭包表达式移到函数调用括号外面。

例如,在 map 函数中使用尾随闭包:

let array = [1, 2, 3, 4]
let squares = array.map { $0 * $0 }
print(squares) // [1, 4, 9, 16]
捕获列表

闭包可以通过捕获列表指定它所捕获的引用如何被持有和操作。捕获列表写在参数列表和闭包体之间,包含一个或者多个捕获项目的列表。

Swift 支持两种捕获列表:

  • 值捕获列表:从周围的上下文中捕获值的引用;
  • 引用捕获列表:从周围的上下文中捕获对象的弱引用或者无主引用。

例如,下面的代码定义了一个函数 makeIncrementer(forIncrement:),用于生成一个从指定值开始的递增器函数。在递增器函数内部,使用了一个捕获列表来捕获变量 runningTotal 的引用,以便实现累加器的功能:

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    let incrementer = { [amount] () -> Int in
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

let incrementByTen = makeIncrementer(forIncrement: 10)
print(incrementByTen()) // 10
print(incrementByTen()) // 20
let incrementByTwo = makeIncrementer(forIncrement: 2)
print(incrementByTwo()) // 2
print(incrementByTwo()) // 4
尾逃递归

Swift 中的尾逃递归可以用来实现类似循环的结构,但是避免了额外的调用栈开销。

在函数的返回语句处使用 return 关键字并且调用函数本身,就可以实现尾逃递归。Swift 编译器可以自动地优化尾逃递归,以便仅使用一个调用帧。

例如,下面的代码定义了一个函数 countdown(_:),用于从一个整数开始递减并输出数值。该函数使用了尾逃递归来实现:

func countdown(_ n: Int) {
    if n <= 0 {
        print("Blast off!")
        return
    }
    print(n)
    countdown(n - 1)
}

countdown(5)
总结

Swift 的闭包是非常强大和灵活的,可以用来编写函数式编程风格的代码。掌握闭包的使用,可以写出更加简洁、高效和可读性好的代码。