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

Swift 闭包

Dans cet article, vous apprendrez ce qu'est une closure, sa syntaxe, et les types de closures en Swift à travers des exemples.

Dans l'article sur les fonctions Swift, nous avons créé une fonction en utilisant la clé de mots func. Cependant, Swift dispose d'un autre type spécial de fonction appelé closure, qui peut être définie sans utiliser la clé de mots func et le nom de la fonction.
Comme les fonctions, les closures peuvent accepter des paramètres et renvoyer des valeurs. Elles contiennent également un ensemble d'instructions qui s'exécutent après l'appel et peuvent être assignées à une variable comme une fonction./Constantes.

Les closures en Swift sont similaires à celles de C et Objective-C.-Les blocks de code en C et les fonctions anonymes dans d'autres langages de programmation sont assez similaires.

Les fonctions globales et les fonctions imbriquées sont en réalité des closures spéciales.

Les formes de fermeture sont :

Fonction globaleFonction imbriquéeexpression de fermeture
Avec un nom mais ne peut capturer aucune valeur.Avec un nom, et peut capturer les valeurs du fonction fermée.Anonyme fermeture, utilisant une syntaxe légère, peut capturer des valeurs selon l'environnement contextuel.

Il y a de nombreux optimisations dans les fermetures Swift :

  • Inférer le type des arguments et des valeurs de retour à partir du contexte

  • Retourner implicitement à partir d'une fermeture d'une seule ligne (c'est-à-dire que le corps de la fermeture n'a qu'une seule ligne de code et qu'il est possible de supprimer return)

  • Il est possible d'utiliser des noms de paramètres simplifiés, tels que $0, $1(commençant par 0, ce qui représente le ième argument...)

  • Fournit une syntaxe de fermeture suivante (trailing closure syntax)

Syntaxe

La définition suivante d'une fermeture reçoit des arguments et retourne un type spécifié :

{(paramètres) -> return type in
   instructions
}

Exemple en ligne

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

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

Hello, World!

La forme de fermeture suivante reçoit deux arguments et retourne une valeur booléenne :

{(Int, Int) -> Bool in
   Instruction1
   Instruction 2
    ---
   Instruction n
}

Exemple en ligne

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

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

Hello, World! Program

expression de fermeture

L'expression de fermeture est une manière de construire une fermeture en ligne en utilisant une syntaxe concise. L'expression de fermeture fournit des optimisations syntaxiques qui rendent l'écriture des fermetures simple et claire.

méthode sorted

La bibliothèque standard Swift fournit un nom appelé sorted(by:) La méthode, basée sur la fonction de fermeture fournie pour le tri, classera les valeurs du tableau de type connu.

Après le tri, la méthode sorted(by:) retournera un nouveau tableau de la même taille que l'original, contenant des éléments du même type et correctement triés. Le tableau original ne sera pas modifié par la méthode sorted(by:).

La méthode sorted(by:) nécessite deux arguments :

  • Tableau de type connu

  • La fonction de fermeture, cette fonction de fermeture doit entrer avec deux valeurs du même type que les éléments de l'arraye, et retourner une valeur de type booléen pour indiquer si, après le tri, le premier argument passé est placé avant ou après le second argument. Si la valeur du premier argument apparaît avant la valeur du second argument, la fonction de fermeture de tri doit retourner true,au contraire retourne false

Exemple en ligne

import Cocoa
let names = ["AT", "AE", "D", "S", "BE"]
// Pour fournir la fonction de tri en utilisant une fonction normale (ou une fonction imbriquée), le type de la fonction de closure doit être (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"]

si le premier chaîne de caractères (s1) est supérieur au deuxième chaîne de caractères (s2) et retourne true, ce qui signifie que s1devrait apparaître dans s2avant. Pour les caractères d'une chaîne de caractères, "greater" signifie "apparaissant plus tard dans l'ordre alphabétique". Cela signifie que le lettre "B" est plus grande que la lettre "A", la chaîne "S" est plus grande que la chaîne "D". Elle effectuera le tri alphabétique inverse, "AT" sera avant "AE".

abréviation de nom de paramètre

Swift fournit automatiquement la fonction d'abréviation de nom de paramètre pour les fonctions en ligne, vous pouvez directement utiliser $0,$1,2pour appeler les paramètres de closure dans l'ordre.

Exemple en ligne

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

$0 et $1représente les premiers et seconds paramètres de type String dans la closure.

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

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

Si vous utilisez des abréviations de noms de paramètres dans l'expression de closure, vous pouvez omettre la définition de ceux-ci dans la liste des paramètres de closure, et le type des abréviations de noms de paramètres sera inféré à partir du type de fonction. Le mot-clé in peut également être omis.

fonctions

En fait, il existe un moyen plus court de rédiger l'expression de closure de l'exemple ci-dessus.

Les fonctions d'opérateurs de SwiftStringLa définition de type définit des informations sur le signe de grandeur (>) de l'implémentation de la chaîne de caractères, qui est une fonction acceptant deuxStringLes paramètres de type et retourBooldes valeurs de type. Ce qui correspond exactement àsort(_:)Le deuxième paramètre de la méthode nécessite un type de fonction conforme. Par conséquent, vous pouvez simplement passer un signe de grandeur, Swift peut automatiquement inférer que vous souhaitez utiliser l'implémentation de la fonction de chaîne de caractères avec le signe de grandeur :

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

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

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

Fermeture en queue

Une closure en queue est une expression de closure écrite après les parenthèses d'une fonction, et la fonction prend en charge de l'appeler cette closure en tant que dernier paramètre.

func someFunctionThatTakesAClosure(closure: () -> Void) {
    // Partie du corps de la fonction
}
// Voici l'appel d'une fonction sans utiliser de closure en queue
someFunctionThatTakesAClosure({
    // Partie principale de la fermeture
)
// Voici l'appel d'une fonction en utilisant une closure en queue
someFunctionThatTakesAClosure() {}}
  // Partie principale de la fermeture
}

Exemple en ligne

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

Après sort() { $0 > $1} en tant que fermeture en queue.

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

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

Attention : Si une fonction nécessite une seule expression de fermeture en paramètre, vous pouvez même omettre les parenthèses lorsque vous utilisez une fermeture en queue.()Omission

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

Valeurs capturées

Les fermetures peuvent capturer des constantes ou des variables dans le contexte de leur définition.

Même si le domaine d'origine de ces constantes et variables n'existe plus, les fermetures peuvent toujours les utiliser et les modifier à l'intérieur de la fonction fermeture.

La forme la plus simple des fermetures en Swift est la fonction imbriquée, c'est-à-dire une fonction définie dans le corps d'une autre fonction.

Les fonctions imbriquées peuvent capturer tous les paramètres, constantes et variables définies par la fonction externe.

Voyons cet exemple :

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

Une fonction makeIncrementor, qui a un paramètre Int appelé amout, et un paramètre externe appelé forIncremet, ce qui signifie que vous devez utiliser ce nom externe lors de l'appel. Le retour est un()-> Intde la fonction.

À l'intérieur de la fonction, une variable runningTotal et une fonction incrementor sont déclarées.

La fonction incrementor ne prend aucun paramètre, mais accède aux variables runningTotal et amount à l'intérieur de la fonction. Cela est dû au fait qu'elle capture les variables runningTotal et amount existantes dans la fonction qui l'enveloppe.

Comme la variable amount n'a pas été modifiée, incrementor capture et stocke une copie de cette variable, et cette copie est stockée avec incrementor.

Donc, quand nous appelons cette fonction, elle accumulera :

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

Les fermetures sont des types de référence

Dans l'exemple ci-dessus, incrementByTen est une constante, mais ces constantes pointent vers des fermetures qui peuvent toujours augmenter la valeur des variables capturées.

C'est parce que les fonctions et les fermetures sont des types de référence.

Peu importe si vous allez fonction/Qu'il s'agisse d'une constante ou d'une variable à laquelle vous assignez une fermeture, vous assignez en réalité une constante/La valeur de la variable est définie en correspondance avec la fonction/Référence de fermeture. Dans l'exemple ci-dessus, incrementByTen pointe une référence à la fermeture, qui est une constante, et non le contenu de la fermeture elle-même.

这也意味着如果您将闭包赋值给了两个不同的常量/变量,两个值都会指向同一个闭包:

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