[Swift] Une note sur la fonction et la fermeture

J'ai étudié pour moi-même, alors prends note

import Foundation

//Le traitement peut être unifié
//Les fonctions sont un type de fermeture
//La maintenabilité et la lisibilité peuvent être améliorées en découpant et en écrivant le processus.
// function
/*
nom de la fonction func(Nom de l'argument: Type, Nom de l'argument: Type ...) ->Type de retour{
Instruction exécutée lorsqu'une fonction est appelée
Renvoie la valeur de retour avec une instruction de retour si nécessaire
}
 */

func double(_ x: Int) -> Int {
    return x * 2
}

double(2) // 4
//Méthode d'exécution
//let nom de la constante = nom de la fonction (nom de l'argument 1: argument 1, nom de l'argument 2: argument 2...)
func functionWithDiscardResult() -> String {
    return "Discardable"
}

_ = functionWithDiscardResult() // Discardable
//argument
func printInt(_ int: Int) {
    print(int)
}

printInt(1) // 1
//Nom d'argument externe et nom d'argument interne
//Argument externe = utilisé lors de l'appel
//Argument interne = ce qui est utilisé dans la fonction
/*
func function name (argument interne: type, argument externe argument interne: type){}
 */


func invite(user: String, to group: String) {
    print("\(user) is invited to \(group)")
}

invite(user: "tanaka", to: "kendo club")

//Omission d'arguments externes_Utilisez ceci
func sum(_ int1: Int, _ int2: Int) -> Int {
    return int1 + int2
}

sum(10, 10) // 20
//Argument par défaut
//Tu peux tout mettre
func greet(user: String = "Anonymos") {
    print("Hello \(user)")
}

greet() // Hello Anonymos
greet(user: "tanaka") 
//Il a trois arguments qui spécifient le mot de recherche, la clé de tri et l'ordre croissant.
//Comme tout ce dont vous avez besoin est un mot-clé de recherche, vous pouvez définir des valeurs par défaut pour les arguments inutiles.
//Si vous souhaitez effectuer une recherche uniquement avec le mot-clé de recherche, ou si vous souhaitez effectuer une recherche en spécifiant la clé de tri, etc., vous pouvez la gérer avec une fonction.
func search(byQuery query: String,
            sortKey: String = "id",
            ascending: Bool = false) -> [Int] {
    return [1, 2, 3]
}

search(byQuery: "query")

//Argument d'entrée-sortie
//Lors de la réaffectation à un argument à l'intérieur d'une fonction en dehors de la fonction, ajoutez inout ou une erreur
//Peut être saisi comme valeur temporaire
//Ajouter & pour appeler l'argument inout
//Erreur lorsqu'il n'est pas attaché: transmission de la valeur de type'String' to an inout parameter requires explicit '&'
func greetA(user: inout String) {
    if user.isEmpty {
        user = "Anonymos"
    }
    print("Hello \(user)")
}
var user: String = ""
greetA(user: &user)

//Argument de longueur variable Argument qui reçoit un nombre arbitraire de valeurs
//Mérite: ne faites pas savoir à l'appelant de la fonction qu'il s'agit d'un tableau
//Jusqu'à une fonction en une
//Devenir un type de baie
func printA(strings: String...) {
    if strings.count == 0 {
        return
    }

    print("first: \(strings[0])")

    for str in strings {
        print("element: \(str)")
    }
}

printA(strings: "abc", "def","ghi")

//first: abc
//element: abc
//element: def
//element: ghi
//Vérification des arguments
func stringA(from: Int) -> String {
    return "\(int)"
}

let int = 1
let double = 1.0

let str1 = stringA(from: int)
// let str2 = stringA(from: double) // error
// Cannot convert value of type 'Double' to expected argument type 'Int'
//Valeur de retour
//non-retour
func greetB(user: String) {
    print("Hello \(user)")
}

greetB(user: "tanaka")
//Comme ci-dessus
func greetC(user: String) -> Void {
    print("Hello \(user)")
}
greetC(user: "tanaka")

//Retour implicite
//Si seulement la valeur de retour, le retour peut être omis
func makeMassage(toUser user: String) -> String {
    "Hello, \(user)"
}

//C'est une erreur
// Missing return in a function expected to return 'String'
/*
S'il existe une valeur autre que la valeur de retour, return ne peut pas être omis.
func makeMassage1(toUser user: String) -> String {
    print(user)
    "Hello, \(user)"
}
 */

//fermeture
/*
Traitement d'un groupe de variables et de constantes dans le périmètre
 { (Argument 1: type, argument 2: type)->Valeur de retour dans
Instruction exécutée lorsque la fermeture est exécutée
Renvoie la valeur de retour avec une instruction de retour si nécessaire
}
 */

//Prend un argument de type Int et renvoie la valeur de retour de type Int qui est doublée (Int) → La fermeture de type Int est exécutée
let doubleA = {(x: Int) -> Int in
    return x * 2
}
doubleA(2) // 4
//Comme le type de fermeture peut être traité de la même manière qu'un type normal, il peut également être utilisé comme type de variable ou de constante ou comme argument de fonction.
let closure: (Int) -> Int
func someFunctionAA(x: (Int) -> Int) {}

closure = { int in
    return int * 2
}
closure(1)

//Inférence de type
var closureA: (String) -> Int

//Lorsque l'argument et la valeur de retour sont spécifiés
closureA = { (str: String) -> Int in
    return str.count
}
closureA("abc") // 3
//Si omis
closureA = { str in
    return str.count * 2
}
closureA("abc") // 6
//Erreur si le type n'est pas décidé
// Unable to infer type of a closure parameter 'str' in the current context
//let butClosure = { str in
//    return str.count * 2
//}

//Méthode d'exécution
//La méthode d'appel est la même que la fonction
//Ajoutez () à la fin du nom de la variable ou du nom de la constante à laquelle la fermeture est affectée et entrez l'argument entre ().,’Organiser par délimiteur
//La valeur de retour est affectée à une variable ou constante
//let nom de la constante = nom de la variable (argument 1, argument 2)
//Les variables et constantes auxquelles la fermeture est affectée sont déduites du type comme type de fermeture.
//Compter le nombre de chaînes
//La même chose est faite, mais le style d'écriture est différent
let lengthOfString = { (string: String) -> Int in  // (String) -> Int
    return string.count
}
lengthOfString("abcdefghijklmnopqrstuvwxyz") // 26

func lengthOfStringA(_ string: String) -> Int {
    return string.count
}
lengthOfStringA("abcdefghijklmnopqrstuvwxyz") // 26
//argument
//Closer ne peut pas utiliser d'arguments externes et par défaut
//Identique à l'omission de l'argument
let add = { (x: Int, y: Int) -> Int in
    print(x + y)
    return x + y
}
add(1,2) // 3
func addFunc(_ x: Int, _ y: Int) -> Int {
    print(x + y)
    return x + y
}

addFunc(1, 2) // 3
//Argument court Omission du nom de l'argument
// $0 ou quelque chose$1 peut être utilisé
let isEqual: (Int, Int) -> Bool = {
    return $0 == $1
}

isEqual(1,1) // true
isEqual(2,1) // false
let keisan: (Int, Int) -> Int = {
    return $0 + $1
}
keisan(1,2) // 3
//Lors de l'utilisation d'arguments abrégés, le type de l'argument n'est pas spécifié dans la définition de fermeture, donc une erreur se produira si le type ne peut pas être déduit de l'extérieur.
//Si vous l'utilisez imprudemment, il s'agit généralement d'un code à faible lisibilité dont vous ne savez pas ce que signifie l'argument,
//Cela peut être très simple, il vaut donc mieux l'utiliser positivement
let numbers = [10,20,30,40]
//officiel
// func filter(_ isIncluded: (Int) throws -> Bool) rethrows -> [Int]
// filter(isIncluded: (Int) throws -> Boo)
//Ce qui suit est le même que ce que je fais, mais il est facile à lire car il est omis
let aaaaaa = numbers.filter { val -> Bool in
    val > 20
}
let bbbbbb = numbers.filter { val in
    val > 20
}
let moreThenTwenty = numbers.filter { $0 > 20 }

aaaaaa          // [30, 40]
bbbbbb          // [30, 40]
moreThenTwenty  // [30, 40]
//Valeur de retour
//Aucun
let emptyReturnValueClosure: () -> Void = {}
//Il existe une
let singleReturnValueClosure: () -> Int = { return 1 }
// ()Et Void sont les mêmes, mais en cas de fermeture, utilisez Void s'il n'y a pas de valeur de retour
// ❌ () -> ()
// ❌ Void -> Void
// ⭕️ () -> Void
//Capturer des variables et des constantes avec des fermetures
/*
Normalement, les variables et constantes définies dans la portée locale ne peuvent pas être utilisées en dehors de la portée locale,
Les variables et constantes référencées dans la clôture en une étape
Même si la portée dans laquelle la fermeture est exécutée est différente de la portée locale dans laquelle les variables et les constantes sont définies
Disponible lors de la fermeture de la fermeture
En effet, la fermeture contient des références à des variables et des constantes dans sa propre portée définie.
C'est ce qu'on appelle la capture
 */

let greeting: (String) -> String
/*-----------------------------*/
do {
    let symbol = "!"
    greeting = { user in
        return "Hello, \(user)\(symbol)"
    }
}

greeting("ken") // "Hello, ken!"
// symbol :::erreur car le symbole est défini dans une autre portée
// Cannot find 'symbol' in scope
//Puisque le message d'accueil constant est déclaré en dehors de la portée do, il peut être utilisé en dehors de do,
//Le symbole constant ne peut pas être utilisé à l'extérieur car il est déclaré dans le cadre de do.
//Cependant, la fermeture affectée au message d'accueil constant peut être exécutée à l'extérieur même si elle utilise le symbole en interne.
//Ceci est réalisé par la fermeture contenant une référence aux variables et aux constantes dans sa propre portée définie par capture.
//La cible de la capture n'est pas la valeur contenue dans la variable ou la constante, mais la variable ou la confiance constante.
//Par conséquent, les modifications apportées aux variables capturées sont reflétées dans l'exécution de la fermeture.
//Exemple
//En dessous, la fermeture affectée au compteur de constantes incrémente la valeur de la variable count de 1 à chaque exécution.
//La valeur initiale du nombre de variables est 0, mais comme il capture la variable elle-même, les mises à jour de la variable sont également conservées.
//Par conséquent, ce sera une valeur différente à chaque exécution.
let counter: () -> Int

do {
    var count = 0
    counter  = {
        count += 1
        return count
    }
}

counter() // 1
counter() // 2
counter() // 3
counter() // 4
counter() // 5

//Plus proche comme argument
//En tant que spécification valable uniquement lors de l'utilisation d'une fermeture comme argument d'une fonction ou d'une autre fermeture
//A des attributs et une fermeture de fin
//Les attributs sont des informations supplémentaires que vous spécifiez pour les fermetures
//La fermeture de fin est une spécification pour améliorer la lisibilité des fonctions qui acceptent des arguments.
//Spécification d'attribut
/*
Il y a deux attributs
  - escaping
  - autoclosure
nom de la fonction func(Argument: @ nom d'attribut, nom du type de fermeture){
Instruction exécutée lorsqu'une fonction est appelée
 }
 */

//func or(_ lhs: Bool, _ rhs: @autoclosure () -> Bool) -> Bool {
//    if lhs {
//        return true
//    } else {
//        return rhs()
//    }
//}
//
//or(true, false) // true
// escaping
//Plus proche qui s'exécute de manière asynchrone
/*
Un attribut qui indique que la fermeture passée comme argument de fonction peut être conservée en dehors de la portée de la fonction.
Le compilateur détermine si la fermeture doit capturer en fonction de la présence ou de l'absence de l'attribut d'échappement.
Si la fermeture peut être conservée en dehors de la portée de la fonction, c'est-à-dire si l'attribut d'échappement est requis
Une capture est requise car elle doit être conservée en dehors de la portée de la fonction jusqu'à ce que la fermeture soit exécutée.
 */

var queue = [() -> Void]()

//Ajoute la fermeture donnée en argument à la file d'attente du tableau
//En d'autres termes, la clôture de cet argument reste hors de portée
//Par conséquent, il est nécessaire de spécifier l'attribut d'échappement dans l'argument de la fonction de mise en file d'attente.
//S'il n'est pas spécifié, une erreur de compilation se produira.
func enqueue(operation: @escaping () -> Void) {
    queue.append(operation)
}

enqueue {
    print("executed")
}
enqueue {
    print("executed")
}
queue.forEach { $0() }

//Les fermetures sans l'attribut d'échappement ne peuvent pas être conservées en dehors de la portée de la fonction
//L'exécution de la fermeture doit être effectuée dans le cadre de la fonction
//La fermeture transmise à la fonction executeTwice n'a pas l'attribut d'échappement, mais elle est exécutée uniquement dans le cadre de la fonction, de sorte qu'une erreur de compilation ne se produit pas.
func executeTwice(operation: () -> Void) {
//Courir ici
    operation()
    operation()
}

executeTwice {
    print(("executed"))
}


//évaluation du retard par fermeture autocloseure
//Attribut pour réaliser l'évaluation du retard en enveloppant l'argument en fermeture
//Ou fonction qui prend deux arguments de type Bool et renvoie la somme logique
//Trouver la somme logique || Une fonction qui se comporte de la même manière que l'opérateur

func or(_ lhs: Bool, _ rhs: Bool) -> Bool {
    if lhs {
        print("true")
        return true
    } else {
        print(rhs)
        return rhs
    }
}

or(true, false)

//Le premier argument est lhs()
//Renvoie rhs au deuxième argument
//A l'intérieur des fonctions lhs et rhs, nous exécutons print afin de voir si chaque fonction a été exécutée.

func orA(_ lhs: Bool, _ rhs: Bool) -> Bool {
    if lhs {
        print("true")
        return true
    } else {
        print(rhs)
        return rhs
    }
}

func lhs() -> Bool {
    print("lhs()A été exécuté")
    return true
}

func rhs() -> Bool {
    print("rhs()A été exécuté")
    return false
}

orA(lhs(), rhs())

//Notation de fermeture de fin pour décrire la fermeture de l'argument entre parenthèses
/*
La fermeture de fin est une notation qui peut être faite en écrivant la fermeture entre () lorsque le dernier argument de la fonction est la fermeture.
 */

func execute(parameter: Int, handler: (String) -> Void) {
    handler("parameter is \(parameter)")
}

//Lorsque vous n'utilisez pas la fermeture de fin
execute(parameter: 1, handler: { string in
    print(string)
})

//Lors de l'utilisation d'une fermeture de fin
execute(parameter: 2) { print($0) }

//S'il n'y a qu'un seul argument, la fonction call () peut également être omise.
func executeA(handler: (String) -> Void) {
    handler("executed")
}

//le même
executeA { valure in
    print(valure)
}
//le même
executeA { print($0) }

//Fonctionne comme une fermeture
/*
Puisqu'une fonction est une sorte de fermeture, elle peut être traitée comme une fermeture. Pour utiliser une fonction comme fermeture, référez-vous à la fonction uniquement par le nom de la fonction.
En traitant une fonction comme une fermeture, vous pouvez l'affecter à une fonction, une variable ou une constante, ou passer un argument d'une autre fonction.
laissez le nom de la constante=Nom de la fonction
L'expression peut même inclure des arguments, multipliés par
laissez le nom de la constante=Nom de la fonction(Nom de l'argument 1:Nom de l'argument 2:)
 */

func doubleA(_ x: Int) -> Int {
    return x * 2
}

let function = doubleA
function(43)

//En définissant la fermeture qui est l'argument de la fonction en tant que fonction, vous pouvez combiner des fermetures en double ou les combiner.
//Vous pouvez donner un nom significatif à la fermeture
//Prenons le cas où la fermeture qui est l'argument de la fonction n'est pas définie comme une fonction.
// Array<Element>En utilisant la carte de types,{ $0 * 2 }J'utilise la fermeture deux fois
//La méthode map renvoie une nouvelle collection, chacune convertie par le processus spécifié par la fermeture.
let array1 = [1,2,3]
let doubleArray1 = array1.map { $0 * 2 }

let array2 = [4,5,6]
let doubleArray2 = array2.map { $0 * 2 }

doubleArray1
doubleArray2

//En traitant la fonction comme une fermeture, l'exemple ci-dessus peut être réécrit comme:
func doubleB(_ x: Int) -> Int {
    return x * 2
}

let array1B = [1,2,3]
let doubleArray1A = array1B.map(doubleB)

let array2B = [4,5,6]
let doubleArray2A = array2B.map(doubleB)

//Dupliquer en définissant la fermeture comme une fonction{ $0 * 2 }Rassemblez le processus en un seul endroit
//Il peut être coupé en donnant le contenu du processus appelé doubleB, il devient donc un code plus lisible.

//Initialisation des variables et des constantes à l'aide d'expressions de fermeture
//Dans certains cas, l'expression de fermeture peut être utilisée pour faciliter la compréhension de l'initialisation de valeurs complexes.
//Supposons que vous souhaitiez implémenter un type qui exprime des carrés 3x3.
//La masse est modélisée dans un tableau à deux dimensions et chaque valeur est directement définie dans le littéral.
var board = [ [1,1,1], [1,1,1], [1,1,1] ]
board

//Au lieu de définir directement ce tableau bidimensionnel, envisagez de décrire la procédure de génération du tableau bidimensionnel.
//Générez des carrés 3X3 en générant 3 lignes avec 3 1s
// Array<Element>Tapez initializer init(reqwationg:count)Génère une valeur avec des arguments répétitifs ajoutés par le nombre de comptes
var boardA = Array(repeating: Array(repeating: 1, count: 3), count: 3)
boardA // [[1, 1, 1], [1, 1, 1], [1, 1, 1]]
//Vous n'avez plus à spécifier chaque élément du tableau.
//Tableau pour combiner les expressions d'initialisation de variables en une seule<Element>Les formules imbriquées pour la génération de type ont rendu difficile la définition de la structure.
//Aussi. Il devient nécessaire de gérer la valeur fixe de 3 à deux endroits.
//L'expression de fermeture peut être utilisée pour combiner une série d'implémentations de procédure d'initialisation en une seule expression. Dans l'exemple suivant, chaque expression imbriquée peut être utilisée pour implémenter une série de procédures d'initialisation. Peut être une formule,
//Dans l'exemple suivant, les expressions imbriquées sont affectées respectivement à la ligne et au tableau des constantes, ce qui facilite la compréhension de la manière dont chacune est générée.
//De plus, comme le nombre de carrés d'un côté est également utilisé comme constante après avoir été déclaré, la gestion peut être unifiée.
var boardB: [[Int]] = {
    let sideLength = 3
    let row = Array(repeating: 1, count: sideLength)
    let board = Array(repeating: row, count: sideLength)
    return board
}()

boardB  // [[1, 1, 1], [1, 1, 1], [1, 1, 1]]

//En faisant ce qui précède, même si le processus d'initialisation des variables et des constantes est compliqué, il devient facile de comprendre comment les valeurs initiales sont générées.

Recommended Posts

[Swift] Une note sur la fonction et la fermeture
Un mémo sur le flux de Rails et Vue
Remarques sur Java GC
Remarques sur la portée
Une note approximative sur les tableaux Ruby et les objets de hachage
Note privée sur AtomicReference
À propos de l'ajout d'une fonction similaire
Une note sur la fonction de départ de Ruby on Rails
Remarques sur les familles de colonnes dans RocksDB
Appeler les fonctions du langage C depuis Swift
Un ingénieur Java a comparé Swift, Kotlin et Java.
Notez que Junit 4 a été ajouté à Android Studio
[Swift] [Débutant] J'ai beaucoup cherché sur #selector
Notes autour de th: champ th: each th: objet de thymeleaf
Traitez les fonctions et fermetures Swift comme des pointeurs de fonction en langage C
Un mémorandum sur les types de données de table et les commandes (Rails)
Questions et réponses sur JDK
À propos de Bean et DI
À propos des classes et des instances
À propos de gets et gets.chomp
À propos de la redirection et du transfert
[Swift] À propos du type d'énumération
À propos de l'encapsulation et de l'héritage
À propos de Serializable et serialVersionUID
Je veux créer une fonction avec kotlin et java!
J'ai essayé JAX-RS et pris note de la procédure
Ajouter une ombre au bouton Swift (et aussi au cercle)