11、Swift 中的闭包

2023-04-25  本文已影响0人  Fred丶Lee

在 Swift 中,闭包是一种引用类型,类似于函数,可以捕获和存储上下文中的值。闭包在 Swift 中非常常见,可以用于简化代码,提高性能和可读性。本文将介绍闭包的基本语法和用法,并提供一些示例代码,以帮助您更好地理解闭包。

闭包的基本语法

闭包的基本语法如下:

{ (parameters) -> return type in
    statements
}

其中,parameters 指定闭包的参数列表,可以为空;return type 指定闭包的返回类型,可以省略;in 关键字分隔参数列表和代码块;statements 是闭包的代码块,用于执行操作并返回结果。

例如,以下是一个简单的闭包,用于计算两个整数的和:

let add: (Int, Int) -> Int = { (a, b) in
    return a + b
}

这个闭包接受两个整数作为参数,并返回它们的和。可以使用以下方式调用它:

let result = add(3, 5)
print(result) // 输出 8

尾随闭包

尾随闭包是一种特殊的闭包语法,可以让代码更加简洁。它将闭包的代码块放在函数调用的括号外面,并在函数调用的括号后面使用一对花括号括起来。例如:

let numbers = [1, 2, 3, 4, 5]
let mapped = numbers.map { $0 * 2 }

在这个例子中,map 方法接受一个闭包作为参数,并对数组中的每个元素执行操作。尾随闭包使代码更加简洁,也更容易阅读。

自动闭包

自动闭包是一种特殊的闭包语法,可以延迟计算。它将表达式封装在一个闭包中,并在需要的时候才执行。例如:

func printIfTrue(_ predicate: () -> Bool) {
    if predicate() {
        print("条件为真")
    }
}

printIfTrue({ 2 > 1 })

在这个例子中,printIfTrue 函数接受一个返回布尔值的闭包作为参数。可以使用自动闭包来简化代码:

func printIfTrue(_ predicate: @autoclosure () -> Bool) {
    if predicate() {
        print("条件为真")
    }
}

printIfTrue(2 > 1)

使用自动闭包时,可以直接传递一个表达式,而不需要显式地创建一个闭包。

闭包的捕获

闭包可以捕获和存储上下文中的值。在 Swift 中,有两种方式可以捕获值:引用捕获和值捕获。

引用捕获会捕获变量或常量的引用,并在闭包中使用该引用。这意味着,如果原始变量或常量发生更改,闭包中捕获的值也会随之更改。例如:

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

let incrementByTen = makeIncrementer(forIncrement: 10)
print(incrementByTen()) // 输出 10
print(incrementByTen()) // 输出 20

在这个例子中,makeIncrementer 函数返回一个闭包,该闭包每次调用时会增加一个固定的量,并返回递增后的值。闭包捕获了 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

在这个例子中,闭包捕获了 amount 常量的值,而不是捕获 runningTotal 变量的引用。因此,runningTotal 的值在多次调用闭包时发生更改,但 amount 的值保持不变。

示例代码

以下是一些示例代码,演示了闭包的不同用法:

// 定义一个接受两个整数并返回它们的和的闭包
let add: (Int, Int) -> Int = { (a, b) in
    return a + b
}
print(add(3, 5)) // 输出 8

// 使用尾随闭包对数组中的每个元素进行平方处理
let numbers = [1, 2, 3, 4, 5]
let squared = numbers.map { $0 * $0 }
print(squared) // 输出 [1, 4, 9, 16, 25]

// 使用自动闭包判断两个整数是否相等
func isEqual(_ a: Int, _ b: Int, _ predicate: @autoclosure () -> Bool) {
    if predicate() {
        print("\(a) 等于 \(b)")
    } else {
        print("\(a) 不等于 \(b)")
    }
}
isEqual(2, 2, 2 == 2) // 输出 "2 等于 2"
isEqual(2, 3, 2 == 3) // 输出 "2 不等于 3"

// 使用引用捕
//获取外部变量的值
func makeCounter() -> () -> Int {
var count = 0
let counter = { () -> Int in
count += 1
return count
}
return counter
}

let counter = makeCounter()
print(counter()) // 输出 1
print(counter()) // 输出 2

// 使用值捕获避免捕获引用
func makeArray() -> [() -> Int] {
var array: [() -> Int] = []
for i in 1...5 {
array.append { [i] () -> Int in
return i
}
}
return array
}

let array = makeArray()
for function in array {
print(function()) // 输出 1, 2, 3, 4, 5
}

// 使用逃逸闭包进行异步处理
func fetchData(completionHandler: @escaping (String) -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
let data = "Hello, world!"
completionHandler(data)
}
}

fetchData { (data) in
print(data) // 输出 "Hello, world!"
}

以上是一些 Swift 中使用闭包的示例,这些示例展示了闭包在不同情况下的灵活性和实用性。闭包是 Swift 中一个重要的特性,对于开发高效和可维护的代码非常有帮助。在开发 Swift 应用程序时,了解和熟练掌握闭包的使用是非常重要的。

上一篇下一篇

猜你喜欢

热点阅读