Swift 閉包的多種形式:包括閉包表達式、尾隨閉包、逃逸閉包等
本文我們將介紹 Swift 中閉包表達式、尾隨閉包和逃逸閉包等相關的內容。如果你尚未安裝 Xcode 和配置 Swift 開發(fā)環(huán)境,請您先閱讀這篇文章。
接下來,我們啟動 Xcode,然后選擇 "File" > "New" > "Playground"。創(chuàng)建一個新的 Playground 并命名為 "Closures"。
在 Swift 中,閉包是自包含的功能塊,可以捕獲和存儲上下文中任意常量和變量的引用。Swift 閉包有多種形式,包括閉包表達式、尾隨閉包、逃逸閉包等。
閉包表達式
閉包表達式語法
閉包表達式是一種輕量級語法,用于表示內聯閉包。它的語法如下:
{ (parameters) -> returnType in
// Closure body
}
相關說明如下:
- parameters:定義了閉包的參數列表。
- returnType:定義了閉包的返回類型。
- in:用于分隔參數列表和閉包體。
創(chuàng)建閉包
了解了閉包表達式的語法之后,我們來創(chuàng)建一個閉包。
Swift Code
// 定義一個閉包,它接受兩個參數并返回它們的總和
let addClosure: (Int, Int) -> Int = { (a: Int, b: Int) -> Int in
return a + b
}
// 調用 addClosure 閉包
let sum = addClosure(2, 3)
print("Sum: \(sum)")
// Output: Sum: 5
在以上例子中,addClosure
是一個接受兩個整數參數并返回它們和的閉包。在閉包表達式中,Swift 可以根據上下文推斷參數類型和返回類型,因此通??梢允÷运鼈儯?/p>
let addClosure: (Int, Int) -> Int = { a, b in
return a + b
}
如果閉包體只包含一條語句,可以省略 return
關鍵字:
let addClosure: (Int, Int) -> Int = { a, b in a + b }
在 Swift 的閉包表達式中,$0
、$1
等是用來表示閉包參數的縮寫形式。這種縮寫形式允許在閉包表達式中直接引用參數,而不需要顯式地命名。所以,以上的代碼,還可以繼續(xù)簡化:
let addClosure: (Int, Int) -> Int = { $0 + $1 }
下面,我們來看一下等價的 TypeScript 代碼。
TypeScript Code
const addClosure: (a: number, b: number) => number = (a, b) => {
return a + b;
};
const sum: number = addClosure(2, 3);
console.log(`Sum: ${sum}`);
// Output: "Sum: 5"
閉包作為函數參數
閉包可以作為函數的參數,使得函數更加靈活。
Swift Code
func performOperation(_ operation: (Int, Int) -> Int, a: Int, b: Int) {
let result = operation(a, b)
print("Result: \(result)")
}
performOperation({ (a: Int, b: Int) -> Int in
return a + b
}, a: 2, b: 3)
// Output:Result: 5
TypeScript Code
function performOperation(operation: (a: number, b: number) => number, a: number, b: number): void {
const result: number = operation(a, b);
console.log(`Result: ${result}`);
}
performOperation((a: number, b: number) => {
return a + b;
}, 2, 3);
// Output: "Result: 5"
閉包作為排序函數的參數
Swift Code
let numbers = [4, 2, 8, 5, 1]
// 使用尾隨閉包
let sortedNumbers = numbers.sorted { $0 < $1 }
print(sortedNumbers)
// Output: [1, 2, 4, 5, 8]
TypeScript Code
const numbers: number[] = [4, 2, 8, 5, 1];
const sortedNumbers: number[] = numbers.sort((a, b) => a - b);
console.log(sortedNumbers);
// Output: [1, 2, 4, 5, 8]
在閉包中捕獲值
在 Swift 中,閉包可以捕獲并存儲它們定義時所在上下文中的常量和變量。即使定義這些常量和變量的原始上下文已經不存在,閉包仍然可以引用和修改這些值。下面我們來舉一個閉包捕獲外部函數的局部變量的示例:
Swift Code
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
let incrementer: () -> Int = {
runningTotal += amount
return runningTotal
}
return incrementer
}
let incrementByTen = makeIncrementer(forIncrement: 10)
print(incrementByTen()) // Output: 10
print(incrementByTen()) // Output: 20
在以上代碼中,incrementByTen
是一個閉包,它捕獲了 makeIncrementer
函數內的 runningTotal
和 amount
變量。即使 makeIncrementer
函數的執(zhí)行已經完成,這些捕獲的變量仍然存在于閉包內。
在 JavaScript 中,函數可以訪問定義它們的函數的作用域中的變量。這個特性被稱為詞法作用域或靜態(tài)作用域。雖然 JavaScript 沒有專門的閉包語法,但函數本身就表現出閉包的行為。
TypeScript Code
function makeIncrementer(amount: number): () => number {
let runningTotal = 0;
return function(): number {
runningTotal += amount;
return runningTotal;
}
}
const incrementByTen = makeIncrementer(10);
console.log(incrementByTen()); // Output: 10
console.log(incrementByTen()); // Output: 20
尾隨閉包
尾隨閉包(Trailing Closures)在 Swift 中是一個非常有用的特性,尤其是當閉包作為函數的最后一個參數時。尾隨閉包語法使得在函數調用時將閉包寫在函數括號之外,使得代碼更加清晰。
let result = someFunction(arg1, arg2) { parameter in
// 閉包體
}
Swift Code
func applyOperation(_ a: Int, _ b: Int, operation: (Int, Int) -> Int) -> Int {
return operation(a, b)
}
// Calling a function using a trailing closure
let result = applyOperation(2, 3) { $0 + $1 }
print("Result: \(result)")
// Output: Result: 5
在以上示例中,applyOperation
函數接受兩個整數和一個閉包作為參數。使用尾隨閉包語法,我們可以將閉包寫在函數調用的括號之外,使得代碼更加簡潔。在 TypeScript 中,并沒有直接的尾隨閉包語法,但可以通過將函數的最后一個參數定義為函數類型來達到類似的效果。
TypeScript Code
function applyOperation(a: number, b: number, operation: (a: number, b: number) => number): number {
return operation(a, b);
}
const result: number = applyOperation(2, 3, (a, b) => a + b);
console.log(`Result: ${result}`);
// Output: "Result: 5"
逃逸閉包
逃逸閉包(Escaping Closures)是一個重要的概念,特別是在處理異步操作和回調時。逃逸閉包與非逃逸閉包的主要區(qū)別在于它們的生命周期:逃逸閉包可以在函數返回之后被調用,而非逃逸閉包則必須在函數返回之前被調用。逃逸閉包是在函數執(zhí)行完畢后才被調用的閉包。在參數列表前加上 @escaping
關鍵字表示該閉包逃逸。
Swift Code
import Foundation
func loadData(completionHandler: @escaping (String) -> Void) {
// 模擬異步操作
DispatchQueue.global().async {
let data = "Hello, Escaping closures!"
DispatchQueue.main.async {
completionHandler(data)
}
}
}
loadData { data in
print("Received: \(data)")
}
// Output: Received: Hello, Escaping closures!
在以上示例中,completionHandler
是一個逃逸閉包,因為它在函數返回之后的某個時間點被調用。在 TypeScript 中,雖然并沒有專門的逃逸閉包的語法,但我們可以通過傳遞函數作為參數,并在異步操作完成后調用該函數來模擬逃逸閉包的效果。
TypeScript Code
function loadData(): Promise<string> {
return new Promise((resolve) => {
// 模擬異步操作
setTimeout(() => {
const data = "Hello, Closures!";
resolve(data);
}, 1000);
});
}
loadData().then(data => {
console.log(`Received: ${data}`);
});
// Output: "Received: Hello, Closures!"
Swift 的逃逸閉包和 TypeScript 的異步操作處理都是處理延時執(zhí)行、異步執(zhí)行的強大工具。它們都允許函數在完成某些操作后再執(zhí)行一些代碼,這在處理網絡請求、數據庫操作等異步任務時非常有用。
本文我們介紹了 Swift 中閉包表達式、尾隨閉包和逃逸閉包等相關的內容。通過與 TypeScript 語法的對比,希望能幫助您更好地理解 Swift 的相關特性。