Closures Swift

Les fermetures sont des blocs de code fonctionnels autonomes qui peuvent être utilisés dans le code ou passés en tant que paramètres.

Les fermetures en Swift sont similaires aux blocs en C et Objective-C et aux fonctions anonymes dans certains autres langages de programmation.

Les fonctions globales et les fonctions imbriquées sont en fait des types spéciaux de fermetures.

Les formes de fermetures sont :

Fonctions globales Fonctions imbriquées Expressions de closure
Ont un nom mais ne peuvent capturer aucune valeur. Ont un nom et peuvent capturer des valeurs depuis leur fonction englobante. Les closures sans nom, avec une syntaxe légère, peuvent capturer des valeurs en fonction du contexte environnant.

Les closures en Swift ont de nombreuses optimisations :

  1. Déduire les types des paramètres et de la valeur de retour à partir du contexte
  2. Retour implicite des closures à expression unique (c'est-à-dire que si le corps de la closure ne contient qu'une seule ligne de code, return peut être omis)
  3. Peut utiliser des noms de paramètres simplifiés, tels que $0, $1 (en partant de 0, représentant les premier et deuxième paramètres...)
  4. Fournit la syntaxe de closure de fin
  5. Syntaxe

    Ce qui suit définit la syntaxe d'une closure qui accepte des paramètres et renvoie un type spécifié :

    {(parameters) -> return type in
       statements
    }
    

    Exemple

    import Cocoa
    
    let studname = { print("Swift 闭包实例。") }
    studname()
    

    La sortie de l'exécution du programme ci-dessus est :

    Swift 闭包实例。
    

    La forme de closure suivante accepte deux paramètres et renvoie une valeur booléenne :

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

    Exemple

    import Cocoa
    
    let divide = {(val1: Int, val2: Int) -> Int in 
       return val1 / val2 
    }
    let result = divide(200, 20)
    print (result)
    

    La sortie de l'exécution du programme ci-dessus est :

    10
    

    Expressions de closure

    Les expressions de closure sont un moyen de construire des closures en ligne à l'aide d'une syntaxe concise. Les expressions de closure offrent certaines optimisations syntaxiques qui simplifient et clarifient l'écriture des closures.


    La méthode sorted

    La bibliothèque standard Swift fournit une méthode nomméesorted(by:)qui trie les valeurs d'un tableau d'un type connu selon la fonction de closure que vous fournissez pour le tri.

    Une fois le tri terminé, la méthode sorted(by:) renvoie un nouveau tableau qui a la même taille que le tableau d'origine, contient des éléments du même type et dont les éléments sont correctement triés. Le tableau d'origine n'est pas modifié par la méthode sorted(by:).

    La méthode sorted(by:) nécessite le passage de deux paramètres :

    • Un tableau d'un type connu
    • Une fonction de closure. Cette fonction de closure doit prendre deux valeurs du même type que les éléments du tableau et renvoyer une valeur booléenne pour indiquer si le premier argument doit apparaître avant le second argument lorsque le tri est terminé. Si la valeur du premier argument apparaît avant la valeur du second argument, la fonction de closure de tri doit renvoyertrue, sinon elle renvoiefalse。

    Exemple

    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)
    

    La sortie de l'exécution du programme ci-dessus est :

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

    Si la première chaîne (s1) est supérieure à la seconde chaîne (s2), la fonction backwards renvoie true, ce qui indique que s1 doit apparaître avant s2 dans le nouveau tableau. Pour les caractères d'une chaîne, "supérieur à" signifie "apparaître plus loin dans l'ordre alphabétique". Cela signifie que la lettre "B" est supérieure à la lettre "A", et que la chaîne "S" est supérieure à la chaîne "D". Le tri se fera par ordre alphabétique inverse, avec "AT" apparaissant avant "AE".


    Noms d'arguments abrégés

    Swift fournit automatiquement des noms d'arguments abrégés pour les closures en ligne. Vous pouvez appeler directement les paramètres de la closure dans l'ordre en utilisant $0, $1, $2.

    Exemple

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

    $0 et $1 représentent les premier et deuxième paramètres de type String dans la fermeture.

    La sortie de l'exécution du programme ci-dessus est :

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

    Si vous utilisez des noms d’arguments abrégés dans une expression de fermeture, vous pouvez omettre leur définition dans la liste des paramètres de la fermeture, et les types des noms d’arguments abrégés seront déduits du type de fonction. Le mot-clé in peut également être omis.


    Fonctions d’opérateur

    En fait, il existe une manière encore plus courte d’écrire l’expression de fermeture dans l’exemple ci-dessus.

    De SwiftStringtype définit l’implémentation de chaîne pour l’opérateur supérieur à (>) qui, en tant que fonction, prend deuxStringparamètres de type et renvoieBoolvaleur de type.sort(_:)correspond au type de fonction requis par le deuxième paramètre de la méthode.

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

    La sortie de l'exécution du programme ci-dessus est :

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

    Fermetures de fin

    Une fermeture de fin est une expression de fermeture écrite après les parenthèses de la fonction, et la fonction prend en charge son appel en tant que dernier argument.

    func someFunctionThatTakesAClosure(closure: () -> Void) {
        // 函数体部分
    }
    
    // 以下是不使用尾随闭包进行函数调用
    someFunctionThatTakesAClosure({
        // 闭包主体部分
    })
    
    // 以下是使用尾随闭包进行函数调用
    someFunctionThatTakesAClosure() {
      // 闭包主体部分
    }
    

    Exemple

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

    Le { $0 > $1 } après sort() est un closure de fin.

    La sortie de l'exécution du programme ci-dessus est :

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

    Remarque : Si la fonction n'a besoin que d'une expression de closure comme unique paramètre, lors de l'utilisation d'un closure de fin, vous pouvez même()l'omettre.

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

    Capture de valeurs

    Les closures peuvent capturer des constantes ou des variables du contexte dans lequel elles sont définies.

    Même si la portée d'origine où ces constantes et variables ont été définies n'existe plus, le closure peut toujours référencer et modifier ces valeurs dans le corps de son closure.

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

    Les fonctions imbriquées peuvent capturer tous les paramètres de leur fonction externe ainsi que les constantes et variables qui y sont définies.

    Regardez 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 nommé amout, et elle a un nom de paramètre externe forIncremet, ce qui signifie que lorsque vous l'appelez, vous devez utiliser ce nom externe. La valeur de retour est un()-> Intfonction.

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

    La fonction incrementor ne prend aucun paramètre, mais elle accède aux variables runningTotal et amount à l'intérieur de son corps de fonction. Ceci est réalisé en capturant les variables runningTotal et amount qui existent déjà dans le corps de la fonction englobante.

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

    Par conséquent, lorsque 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())
    

    La sortie de l'exécution du programme ci-dessus est :

    10
    20
    30
    

    Les closures sont des types de référence

    Dans l'exemple ci-dessus, incrementByTen est une constante, mais la closure vers laquelle ces constantes pointent peut encore augmenter la valeur de la variable qu'elle a capturée.

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

    Que vous affectiez une fonction/closure à une constante ou à une variable, vous définissez en réalité la valeur de cette constante/variable à une référence à la fonction/closure correspondante. Dans l'exemple ci-dessus, la référence à la closure vers laquelle pointe incrementByTen est une constante, non le contenu de la closure lui-même.

    Cela signifie également que si vous affectez la closure à deux constantes/variables différentes, les deux valeurs pointeront vers la même 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())
    

    La sortie de l'exécution du programme ci-dessus est :

    50
    Autres extensions