📅  最后修改于: 2023-12-03 15:35:12.875000             🧑  作者: Mango
在 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 的闭包是非常强大和灵活的,可以用来编写函数式编程风格的代码。掌握闭包的使用,可以写出更加简洁、高效和可读性好的代码。