English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Swift闭包

In questo articolo, imparerai cosa sono i blocchi, la sintassi e i tipi di blocchi in Swift.

Nel testo della funzione Swift, abbiamo creato una funzione utilizzando la parola chiave func. Ma in Swift c'è anche un altro tipo speciale di funzione chiamato blocco, che può essere definito senza la parola chiave func e il nome della funzione.
Come le funzioni, i blocchi possono accettare parametri e restituire valori. Contengono anche un insieme di istruzioni che vengono eseguite dopo la chiamata e possono essere assegnati a variabili o costanti come funzioni.

I blocchi in Swift sono simili ai blocchi in C e Objective-C e a funzioni anonime in altri linguaggi di programmazione.

La funzione globale e la funzione annidata sono in realtà blocchi speciali.

La forma dei blocchi è:

Funzione globaleFunzione annidata闭包表达式
Blocchi con nome ma non possono catturare alcun valore.Blocchi con nome, possono anche catturare valori all'interno della funzione chiusa.Blocchi anonimi, utilizzando una sintassi leggera, possono catturare valori dall'ambiente contestuale.

Swift ha molte ottimizzazioni per i blocchi:

  • Inferenza del tipo di parametro e valore di ritorno dal contesto

  • Il ritorno implicito da espressioni di blocco singole (ovvero il corpo del blocco ha solo una riga di codice e può essere omesso return)

  • 可以使用简化参数名,如$0, $1(从0开始,表示第i个参数...)}

  • 提供了尾随闭包语法(Trailing closure syntax)

语法

以下定义了一个接收参数并返回指定类型的闭包语法:

{(parameters) -> return type in
   statements
}

Esempio online

let simpleClosure = {
    print("Hello, World!")
}
simpleClosure()

以上程序执行输出结果为:

Hello, World!

以下闭包形式接收两个参数并返回布尔值:

{(Int, Int) -> Bool in
   Statement1
   Statement 2
    ---
   Statement n
}

Esempio online

let simpleClosure: (String) -> (String) = { name in
    
    let greeting = "Hello, World! " + "Program"
    return greeting
}
let result = simpleClosure("Hello, World")
print(result)

以上程序执行输出结果为:

Hello, World! Program

闭包表达式

闭包表达式是一种利用简洁语法构建内联闭包的方式。闭包表达式提供了一些语法优化,使得撰写闭包变得简单明了。

sorted 方法

Swift 标准库提供了名为 sorted(by:) 的方法,会根据您提供的用于排序的闭包函数将已知类型数组中的值进行排序。

排序完成后,sorted(by:) 方法会返回一个与原数组大小相同,包含同类型元素且元素已正确排序的新数组。原数组不会被 sorted(by:) 方法修改。

sorted(by:)方法需要传入两个参数:

  • 已知类型的数组

  • 闭包函数,该闭包函数需要传入与数组元素类型相同的两个值,并返回一个布尔类型值来表明当排序结束后传入的第一个参数排在第二个参数前面还是后面。如果第一个参数值出现在第二个参数值前面,排序闭包函数需要返回 true,反之返回 false

Esempio online

import Cocoa
let names = ["AT", "AE", "D", "S", "BE"]
// 使用普通函数(或内嵌函数)提供排序功能,闭包函数类型需为(String, String) -> Bool。
func backwards(s1: String, s2: String) -> Bool {
    return s1 > s2
}
var reversed = names.sorted(by: backwards)
print(reversed)

以上程序执行输出结果为:

["S", "D", "BE", "AT", "AE"]

Se la prima stringa (s1) è maggiore della seconda stringa (s2), la funzione backwards restituisce true, il che significa che s1 dovrebbe apparire prima di s2 nell'array nuovo. Per i caratteri delle stringhe, "maggiore" significa "appare più tardi nell'ordine alfabetico". Questo significa che la lettera "B" è maggiore della lettera "A", la stringa "S" è maggiore della stringa "D". Effettuerà una sortita inversa, "AT" apparirà prima di "AE".

abbreviazione dei nomi dei parametri

Swift fornisce automaticamente la funzione di abbreviazione dei nomi dei parametri per le funzioni inline, puoi chiamare direttamente i parametri della chiusura con $0, $1, $2 in ordine.

Esempio online

import Cocoa
let names = ["AT", "AE", "D", "S", "BE"]
var reversed = names.sorted(by: { $0 > $1 })
print(reversed)

$0 e $1 rappresentano il primo e il secondo parametro di tipo String nella chiusura.

以上程序执行输出结果为:

["S", "D", "BE", "AT", "AE"]

Se usi abbreviazioni di nome dei parametri in un'espressione di chiusura, puoi omettere la loro definizione nella lista dei parametri della chiusura e il tipo dell'abbreviazione del nome del parametro sarà inferito dal tipo della funzione. La parola chiave 'in' può anche essere omessa.

funzione operatore

In realtà, c'è un modo ancora più breve per scrivere l'espressione di chiusura nell'esempio sopra.

funzione operatore in SwiftStringdefinisce qualcosa su come usare il maggiore di (>) implementazione di stringa, che come funzione accetta dueStringparametro e restituisceBoolvalori di tipo. E questo corrisponde asort(_):Il secondo parametro del metodo richiede un tipo di funzione che corrisponde. Quindi, puoi semplicemente passare un maggiore di, Swift può inferire automaticamente che vuoi utilizzare l'espressione di funzione di stringa con il maggiore di:

import Cocoa
let names = ["AT", "AE", "D", "S", "BE"]
var reversed = names.sorted(by: >)
print(reversed)

以上程序执行输出结果为:

["S", "D", "BE", "AT", "AE"]

Chiusura trailing

Una chiusura trailing è un'espressione di chiusura scritta dopo i parentesi della funzione, che la funzione supporta come ultimo argomento da chiamare.

func someFunctionThatTakesAClosure(closure: () -> Void) {
    // Corpo della funzione
}
// Ecco come si chiama una funzione senza chiusura trailing
someFunctionThatTakesAClosure({
    // Corpo della chiusura
}
// Ecco come si chiama una funzione con chiusura trailing
someFunctionThatTakesAClosure() {
  // Corpo della chiusura
}

Esempio online

import Cocoa
let names = ["AT", "AE", "D", "S", "BE"]
//Closure trailing
var reversed = names.sorted() { $0 > $1 }
print(reversed)

La { $0 > $1 } dopo sort() è una closure trailing.

以上程序执行输出结果为:

["S", "D", "BE", "AT", "AE"]

Attenzione: Se la funzione ha bisogno solo di un'espressione di closure come parametro, quando si utilizza la closure trailing, si può anche mettere()Saltato.

reversed = names.sorted { $0 > $1 }

Valori catturati

Le closures possono catturare costanti o variabili nel contesto in cui sono definite.

Anche se il dominio di origine di queste costanti o variabili non esiste più, le closures possono ancora riferirsi e modificare questi valori all'interno della funzione di closure.

La forma più semplice di closure in Swift è la funzione annidata, ossia la funzione definita nel corpo di un'altra funzione.

Le funzioni annidate possono catturare tutti i parametri e le costanti o le variabili definite nelle funzioni esterne.

Vediamo questo esempio:

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

Una funzione makeIncrementor che ha un parametro di tipo Int chiamato amout e un parametro esterno chiamato forIncremet, il che significa che quando la chiama, deve utilizzare questo nome esterno. Il valore di ritorno è un-> Intdi funzione.

All'interno della funzione, è stata dichiarata la variabile runningTotal e una funzione incrementor.

La funzione incrementor non prende alcun parametro, ma accede alle variabili runningTotal e amount all'interno del corpo della funzione. Questo è perché cattura le variabili runningTotal e amount esistenti nel corpo della funzione che la contiene.

Poiché non è stata modificata la variabile amount, incrementor cattura e memorizza una copia di quella variabile, che viene memorizzata insieme a incrementor.

Quindi chiamando questa funzione si accumulerà:

import Cocoa
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}
let incrementByTen = makeIncrementor(forIncrement: 10)
//返回的值为10
print(incrementByTen())
//返回的值为20
print(incrementByTen())
//返回的值为30
print(incrementByTen())

以上程序执行输出结果为:

10
20
30

Le closures sono di tipo riferimento

Nel caso di esempio, incrementByTen è una costante, ma queste costanti possono ancora aumentare il valore delle variabili catturate.

Questo è perché le funzioni e le closures sono di tipo riferimento.

Indipendentemente dal fatto che assegni una funzione/closure a una costante o a una variabile, stai effettivamente impostando il valore della costante/variabile come un riferimento alla funzione/closure corrispondente. Nel caso di esempio, incrementByTen punta a un riferimento alla closure che è una costante, non al contenuto della closure stessa.

Questo significa che se assegni un closure a due diverse costanti/variabili, entrambi i valori faranno riferimento allo stesso closure:

import Cocoa
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}
let incrementByTen = makeIncrementor(forIncrement: 10)
//返回的值为10
incrementByTen()
//返回的值为20
incrementByTen()
//返回的值为30
incrementByTen()
//返回的值为40
incrementByTen()
let alsoIncrementByTen = incrementByTen
//返回的值也为50
print(alsoIncrementByTen())

以上程序执行输出结果为:

50