Swift From Scratch Paramètres de fonction, types et imbrication

Dans l'article précédent, nous avons exploré les bases des fonctions dans Swift. Les fonctions ont cependant beaucoup plus à offrir. Dans cet article, nous poursuivons notre exploration des fonctions et examinons leurs paramètres, leur imbrication et leurs types..

1. Noms de paramètres locaux et externes

Noms de paramètres

Reprenons l'un des exemples de l'article précédent. le printMessage (message :) fonction définit un paramètre, message.

func printMessage (message: String) print (message)

Nous assignons un nom, message, au paramètre et utiliser ce nom quand on appelle la fonction.

printMessage (message: "Hello, world!")

Mais notez que nous utilisons également le même nom pour référencer la valeur du paramètre dans le corps de la fonction..

func printMessage (message: String) print (message)

Dans Swift, un paramètre a toujours un local nom du paramètre, et éventuellement un externe le nom du paramètre. Dans l'exemple, les noms de paramètre local et externe sont identiques.

Directives API

À compter de Swift 3, l'équipe Swift a défini un ensemble clair de directives concernant les API. Je ne vais pas entrer dans ces lignes directrices dans ce tutoriel, mais je tiens à souligner que la définition de la printMessage (message :) la fonction s'écarte de ces directives. Le nom de la fonction contient le mot message, et le paramètre est également nommé message. En d'autres termes, nous nous répétons.

Ce serait plus élégant si nous pouvions invoquer le printMessage (message :) fonctionner sans message mot-clé. C'est ce que j'ai en tête.

printMessage ("Hello, world!")

C'est possible et cela correspond davantage aux directives de l'API Swift. Mais qu'est-ce qui est différent? La différence est facile à repérer si nous examinons la définition de fonction mise à jour. L’exemple mis à jour en révèle également davantage sur l’anatomie des fonctions dans Swift..

func printMessage (_ message: String) print (message)

Dans une définition de fonction, chaque paramètre est défini par un nom de paramètre externe, un nom de paramètre local, un signe deux-points et le type du paramètre. Si les noms de paramètre local et externe sont identiques, nous écrivons le nom du paramètre une seule fois. C’est pourquoi le premier exemple définit un nom de paramètre, message.

Si nous ne voulons pas attribuer un nom de paramètre externe à un paramètre, nous utilisons le _, un trait de soulignement. Cela informe le compilateur que le paramètre n'a pas de nom de paramètre externe, ce qui signifie que nous pouvons omettre le nom du paramètre lorsque la fonction est appelée..

Noms de paramètres externes

Objective-C est connu pour ses noms de méthode longs. Bien que cela puisse paraître maladroit et inélégant aux étrangers, cela rend les méthodes faciles à comprendre et, si bien choisies, très descriptives. L’équipe Swift a compris cet avantage et a introduit les noms de paramètres externes dès le premier jour.

Lorsqu'une fonction accepte plusieurs paramètres, il n'est pas toujours évident de savoir quel argument correspond à quel paramètre. Regardez l'exemple suivant pour mieux comprendre le problème. Notez que les paramètres n'ont pas de nom de paramètre externe.

func power (_ a: Int, _ b: Int) -> Int résultat var = = pour _ en 1… 

le Puissance(_:_:) la fonction augmente la valeur de une par l'exposant b. Les deux paramètres sont de type Int. Bien que la plupart des gens passent intuitivement la valeur de base comme premier argument et l’exposant comme second argument, cela n’est pas clair pour le type, le nom ou la signature de la fonction. Comme nous l'avons vu dans l'article précédent, invoquer la fonction est simple.

puissance (2, 3)

Pour éviter toute confusion, nous pouvons donner les paramètres d'une fonction à des noms externes. Nous pouvons ensuite utiliser ces noms externes lorsque la fonction est appelée pour indiquer sans ambiguïté quel argument correspond à quel paramètre. Jetez un coup d'œil à l'exemple mis à jour ci-dessous.

func power (base a: Int, exposant b: Int) -> Int résultat var = = pour _ en 1… 

Notez que le corps de la fonction n'a pas changé depuis les noms locaux. Cependant, lorsque nous appelons la fonction mise à jour, la différence est nette et le résultat est moins déroutant..

puissance (base: 2, exposant: 3)

Bien que les types des deux fonctions soient identiques, (Int, Int) -> Int, les fonctions sont différentes. En d'autres termes, la deuxième fonction n'est pas une redéclaration de la première fonction. La syntaxe à utiliser pour appeler la deuxième fonction peut vous rappeler Objective-C. Non seulement les arguments sont clairement décrits, mais la combinaison des noms de fonction et de paramètre décrit également le but de la fonction..

Dans certains cas, vous souhaitez utiliser le même nom pour les noms de paramètre local et externe. Cela est possible et il n’est pas nécessaire de saisir deux fois le nom du paramètre. Dans l'exemple suivant, nous utilisons base et exposant comme noms de paramètres locaux et externes.

func power (base: Int, exposant: Int) -> Int résultat var = base pour _ en 1… 

En définissant un nom pour chaque paramètre, le nom du paramètre sert de nom local et externe au paramètre. Cela signifie également que nous devons mettre à jour le corps de la fonction..

Il est important de noter qu'en fournissant un nom externe à un paramètre, vous devez utiliser ce nom pour appeler la fonction. Cela nous amène aux valeurs par défaut.

Les valeurs par défaut

Nous avons abordé les valeurs de paramètre par défaut dans l'article précédent. C'est la fonction que nous avons définie dans cet article.

func printDate (date: date, format: String = "YY / MM / jj") -> String let dateFormatter = DateFormatter () dateFormatter.dateFormat = le format de retour dateFormatter.string (à partir de: date)

Que se passe-t-il si nous ne définissons pas de nom de paramètre externe pour le second paramètre, qui a une valeur par défaut?

func printDate (date: date, _ format: String = "AA / MM / jj") -> String let dateFormatter = DateFormatter () dateFormatter.dateFormat = le format de retour dateFormatter.string (à partir de: date)

Le compilateur ne semble pas s'en soucier. Mais est-ce ce que nous voulons? Il est préférable de définir un nom de paramètre externe sur des paramètres facultatifs (paramètres avec une valeur par défaut) pour éviter toute confusion et toute ambiguïté..

Notez que nous nous répétons encore dans l'exemple précédent. Il n’est pas nécessaire de définir un nom de paramètre externe pour le rendez-vous amoureux paramètre. L'exemple suivant montre ce que le printDate (_: format :) la fonction ressemblerait si nous suivions les directives de l'API Swift.

func printDate (_ date: date, format: String = "AA / MM / jj") -> String let dateFormatter = DateFormatter () dateFormatter.dateFormat = le format de retour dateFormatter.string (à partir de: date)

Nous pouvons maintenant invoquer le formatDate (_: format :) fonctionner sans utiliser le rendez-vous amoureux étiquette pour le premier paramètre et avec un format de date optionnel.

printDate (Date ()) printDate (Date (), format: "jj / mm / aa")

2. Paramètres et mutabilité

Revenons sur le premier exemple de ce tutoriel, le printMessage (_ :) une fonction. Que se passe-t-il si nous changeons la valeur du message paramètre à l'intérieur du corps de la fonction?

func printMessage (_ message: String) message = "Print: \ (message)" print (message)

Il ne faut pas longtemps au compilateur pour commencer à se plaindre.

Les paramètres d'une fonction sont des constantes. En d'autres termes, bien que nous puissions accéder aux valeurs des paramètres de fonction, nous ne pouvons pas modifier leur valeur. Pour contourner cette limitation, nous déclarons une variable dans le corps de la fonction et utilisons cette variable à la place..

func printMessage (_ message: String) var message = message message = "Imprimer: \ (message)" print (message)

3. Paramètres variadiques

Bien que le terme puisse sembler étrange au début, les paramètres variadiques sont courants en programmation. Un paramètre variadique est un paramètre qui accepte zéro ou plusieurs valeurs. Les valeurs doivent être du même type. L'utilisation de paramètres variadiques dans Swift est simple, comme l'illustre l'exemple suivant.

func sum (_ args: Int…) -> Int var result = 0 pour a dans args result + = a return result sum (1, 2, 3, 4)

La syntaxe est facile à comprendre. Pour marquer un paramètre comme variable, vous ajoutez trois points au type du paramètre. Dans le corps de la fonction, le paramètre variadic est accessible sous forme de tableau. Dans l'exemple ci-dessus, args est un tableau de Int valeurs.

Parce que Swift a besoin de savoir quels arguments correspondent à quels paramètres, un paramètre variadique doit être le dernier paramètre. Cela implique aussi qu’une fonction peut avoir au plus un paramètre variadique.

Ce qui précède s'applique également si une fonction a des paramètres avec des valeurs par défaut. Le paramètre variadic devrait toujours être le dernier paramètre.

4. Paramètres In-Out

Plus tôt dans ce tutoriel, vous avez appris que les paramètres d'une fonction sont des constantes. Si vous souhaitez transmettre une valeur à une fonction, la modifier dans la fonction et la transmettre hors de la fonction, vous avez besoin des paramètres d'entrée-sortie..

L'exemple suivant montre un exemple d'utilisation des paramètres d'entrée-sortie dans Swift et à quoi ressemble la syntaxe..

func prefixString (_ chaîne: chaîne inout, avec le préfixe: chaîne) chaîne = préfixe + chaîne

Nous définissons le premier paramètre en tant que paramètre in-out en ajoutant le paramètre inout mot-clé. Le second paramètre est un paramètre régulier avec un nom externe de avecChaîne et un nom local de préfixe. Comment invoquer cette fonction?

var input = "world!" prefixString (& input, avec: "Hello,")

Nous déclarons une variable, contribution, de type Chaîne et le passer à la prefixString (_: avec :) une fonction. Le deuxième paramètre est un littéral de chaîne. En appelant la fonction, la valeur de contribution la variable devient Bonjour le monde!. Notez que le premier argument est préfixé par une esperluette, Et, pour indiquer qu'il s'agit d'un paramètre in-out.

Il va sans dire que les constantes et les littéraux ne peuvent pas être passés en tant que paramètres in-out. Le compilateur renvoie une erreur lorsque vous procédez comme illustré dans les exemples suivants..

Il est évident que les paramètres d'entrée-sortie ne peuvent pas avoir de valeurs par défaut ou être variadiques. Si vous oubliez ces informations, le compilateur vous le rappelle gentiment avec une erreur..

5. Nidification

En C et Objective-C, les fonctions et méthodes ne peuvent pas être imbriquées. Dans Swift, cependant, les fonctions imbriquées sont assez courantes. Les fonctions que nous avons vues dans cet article et dans l'article précédent sont des exemples de fonctions globales. Elles sont définies dans la portée globale..

Lorsque nous définissons une fonction dans une fonction globale, nous appelons cette fonction une fonction imbriquée. Une fonction imbriquée a accès aux valeurs définies dans sa fonction englobante. Regardez l'exemple suivant pour mieux comprendre cela..

func printMessage (_ message: String) let a = "bonjour le monde" func printHelloWorld () print (a)

Bien que les fonctions de cet exemple ne soient pas très utiles, elles illustrent l’idée des fonctions imbriquées et de la capture de valeurs. le printHelloWorld () la fonction est uniquement accessible depuis le printMessage (_ :) une fonction.

Comme illustré dans l'exemple, le printHelloWorld () la fonction a accès à la constante une. La valeur est capturée par la fonction imbriquée et est donc accessible à partir de cette fonction. Swift prend en charge la capture des valeurs, y compris la gestion de la mémoire de ces valeurs.

6. Types de fonction

Fonctionne comme paramètres

Dans l'article précédent, nous avons brièvement abordé les types de fonctions. Une fonction a un type particulier, composé des types de paramètre de la fonction et de son type de retour. le printMessage (_ :) la fonction, par exemple, est de type (Chaîne) -> (). Rappelez-vous que () symbolise Vide, ce qui équivaut à un tuple vide.

Chaque fonction ayant un type, il est possible de définir une fonction qui accepte une autre fonction en tant que paramètre. L'exemple suivant montre comment cela fonctionne.

func printMessage (_ message: String) print (message) func printMessage (_ message: String, avec function: (String) -> ()) function (message) let myMessage = "Bonjour tout le monde!" printMessage (myMessage, avec: printMessage)

le printMessage (_: avec :) function accepte une chaîne en tant que premier paramètre et une fonction de type (Chaîne) -> () comme second paramètre. Dans le corps de la fonction, la fonction que nous passons est invoquée avec le message argument.

L’exemple illustre également comment nous pouvons invoquer le printMessage (_: avec :) une fonction. le mon message constante est passée en tant que premier argument et le printMessage (_ :) fonctionne comme second argument. À quel point cela est cool?

Fonctionne comme type de retour

Il est également possible de renvoyer une fonction d'une fonction. L'exemple suivant est un peu artificiel, mais il illustre à quoi ressemble la syntaxe.

func compute (_ addition: Bool) -> (Int, Int) -> Int func add (_ a: Int, _ b: Int) -> Int retour a + b func soustrait (_ a: Int, _ b: Int) -> Int return a - b si addition return add else retour soustraction let computeFunction = compute (true) let result = computeFunction (1, 2) print (result)

le calculer(_:) function accepte un booléen et retourne une fonction de type (Int, Int) -> Int. le calculer(_:) fonction contient deux fonctions imbriquées qui sont aussi de type (Int, Int) -> Int, ajouter(_:_:) et soustraire(_:_:).

le calculer(_:) la fonction renvoie une référence à la ajouter(_:_:) ou la soustraire(_:_:) fonction, basée sur la valeur de la une addition paramètre.

L’exemple montre également comment utiliser le calculer(_:) une fonction. Nous stockons une référence à la fonction qui est retournée par le calculer(_:) fonctionner dans le computeFunction constant. Nous appelons ensuite la fonction stockée dans computeFunction, en passant 1 et 2, stocker le résultat dans le résultat constante et imprimer la valeur de résultat dans la sortie standard. L'exemple peut paraître complexe, mais il est en fait facile à comprendre si vous savez ce qui se passe.

Conclusion

Vous devez maintenant bien comprendre le fonctionnement des fonctions dans Swift et ce que vous pouvez en faire. Les fonctions sont fondamentales pour la langue Swift et vous les utiliserez beaucoup lorsque vous travaillerez avec Swift..

Dans le prochain article, nous nous plongeons dans les fermetures - une construction puissante qui rappelle les blocs en C et Objective-C, les fermetures en JavaScript et les lambdas en Ruby.

Si vous souhaitez apprendre à utiliser Swift 3 pour coder des applications réelles, consultez notre cours Créer des applications iOS avec Swift 3. Que vous débutiez dans le développement d'applications iOS ou que vous souhaitiez passer de Objective-C à un autre bien sûr, vous allez commencer avec Swift pour le développement d'applications.