Les fonctions sont des morceaux de code autonomes qui exécutent une tâche spécifique. Vous donnez à une fonction un nom qui identifie ce qu'elle fait, et ce nom est utilisé pour "appeler" la fonction.
Définir une fonction Swift
Chaque fonction en Swift a un type, composé des types de paramètres de la fonction et du type de retour. Vous pouvez utiliser ce type comme n'importe quel autre type dans Swift, ce qui facilite le passage de fonctions en tant que paramètres à d'autres fonctions et le renvoi de fonctions à partir de fonctions. Les fonctions peuvent également être écrites dans d'autres fonctions pour encapsuler des fonctionnalités utiles dans une portée de fonction imbriquée.
Il est important de comprendre la syntaxe des fonctions en Swift pour pouvoir les utiliser correctement dans votre code. Voici un exemple simple de définition de fonction :
func saluer(nom: String) -> String {
return "Bonjour, \(nom)!"
}
Dans cet exemple, nous définissons une fonction saluer qui prend un argument en entrée nommé nom de type String et renvoie une valeur de type String. Lorsque la fonction est appelée, elle renvoie le message de bienvenue formé avec le nom fourni.
Appeler une fonction
Pour appeler une fonction, il suffit de spécifier le nom de la fonction suivi des arguments nécessaires entre parenthèses. Par exemple :
let message = saluer(nom: "Jean")
print(message)
// Bonjour, Jean!
Nous appelons la fonction en spécifiant son nom, saluer, suivi de l'argument nom: "Jean" entre parenthèses. La valeur de retour de la fonction est assignée à la constante message et affichée à l'aide de la fonction print.
Les paramètres
Comme nous venons de le voir, lorsque vous définissez une fonction, vous pouvez si vous le souhaitez définir une ou plusieurs valeurs nommées et typées que la fonction prend en entrée, appelées paramètres.
Vous pouvez définir en option un type de valeur que la fonction transmettra en sortie lorsqu'elle sera terminée, appelé son type de retour.
func greet(person: String) -> String {
let greeting = "Bonjour, " + person + "!"
return greeting
}
print(greet(person: "Anne"))
// "Bonjour, Anne!"
Fonction sans paramètre
func sayHelloWorld() -> String {
return "Bonjour à tous"
}
print(sayHelloWorld())
// "Bonjour à tous"
La définition d'une fonction a toujours besoin de parenthèses après le nom de la fonction, même si elle ne prend aucun paramètre. Le nom de la fonction est également suivi d'une paire de parenthèses vides lorsque la fonction est appelée.
Fonction avec plusieurs paramètres
func greet(person: String, alreadyGreeted: Bool) -> String {
if alreadyGreeted {
...
} else {
...
}
}
print(greet(person: "Tom", alreadyGreeted: true))
Les fonctions peuvent avoir plusieurs paramètres d'entrée, qui sont écrits entre les parenthèses de la fonction, séparés par des virgules.
Valeur de retour
Les fonctions n'ont nécessairement à définir un type de retour. Voici une version de la fonction greet(person:), qui "affiche" sa propre valeur String plutôt que de la renvoyer :
func greet(person: String) {
print("Hello, \(person)!")
}
greet(person: "Maxime")
// Cela va afficher : "Hello, Maxime!"
Comme il n'est pas nécessaire de renvoyer une valeur, la définition de la fonction n'inclut pas la flèche de retour ( ->) ou un type de retour.
Vous pouvez utiliser les tuples comme type de retour pour une fonction afin de renvoyer plusieurs valeurs dans le cadre d'une valeur de retour composé.
func minMax(array: [Int]) -> (min: Int, max: Int) {
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
La fonction minMax(array:) renvoie un tuple contenant deux valeurs Int. Ces valeurs sont étiquetées min et max sont donc accessibles par leur nom lors de l'interrogation de la valeur de retour de la fonction.
let bounds = minMax(array: [8, -6, 2, 109, 3, 71])
print("min is \(bounds.min) and max is \(bounds.max)")
// Prints "min is -6 and max is 109"
Retour de tuples facultatifs
Si le type de tuple à renvoyer à partir d'une fonction a le potentiel de n'avoir "aucune valeur" pour le tuple entier, vous pouvez utiliser un type de retour de tuple facultatif ou optionnel pour refléter le fait que le tuple entier peut être nil.
func minMax(array: [Int]) -> (min: Int, max: Int)? {
if array.isEmpty { return nil }
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
Vous pouvez utiliser une liaison facultative pour vérifier si cette version de la fonction minMax(array:) renvoie une valeur de tuple réelle ou nil :
if let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) {
print("min : \(bounds.min) and max : \(bounds.max)")
} // "min : -6 and max : 109"
Fonction avec retour implicite
Si le corps entier de la fonction est une seule expression, la fonction renvoie implicitement cette expression. Toute fonction que vous écrivez sur une seule ligne peut omettre le return.
func greeting(for person: String) -> String {
"Bonjour, " + person + "!"
}
// Equivaut à :
func anotherGreeting(for person: String) -> String {
return "Bonjour, " + person + "!"
}
Les étiquettes d'arguments et paramètres
Chaque paramètre de fonction possède à la fois une étiquette d'argument et un nom de paramètre. L'étiquette d'argument est utilisée lors de l'appel de la fonction; chaque argument est écrit avec son étiquette d'argument devant lui. Le nom du paramètre est utilisé dans l'implémentation de la fonction. Par défaut, les paramètres utilisent leur nom de paramètre comme étiquette d'argument.
Vous écrivez une étiquette d'argument avant le nom du paramètre, séparé par un espace :
func greet(person: String, from hometown: String) -> String {
return "Bonjour \(person)! Vous venez de \(hometown)."
}
print(greet(person: "Michel", from: "Lille"))
// "Bonjour Michel! Vous venez de Lille."
Omettre les étiquettes d'arguments
Si vous ne voulez pas d'étiquette d'argument pour un paramètre, écrivez un trait de soulignement _ (underscore) au lieu d'une étiquette d'argument explicite pour ce paramètre.
func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
// firstParameterName et secondParameterName
// font références aux valeurs d'argument
// des premier et deuxième paramètres
}
someFunction(1, secondParameterName: 2)
Si un paramètre a une étiquette d'argument, l'argument doit être étiqueté lorsque vous appelez la fonction.
Valeur par défaut des paramètres
Vous pouvez définir une valeur par défaut pour n'importe quel paramètre d'une fonction en attribuant une valeur au paramètre après le type de ce paramètre. Si une valeur par défaut est définie, vous n'êtes pas obliger d'inclure ce paramètre dans l'appel de la fonction.
func someFunction(parameterSansDefault: Int, parameterWithDefault: Int = 12) {
// Si tu oublis d'indiquer un deuxième argument lors de l'appel de cette fonction
// la valeur du paramètre parameterWithDefault sera égale à 12
}
someFunction(parameterSansDefault: 3, parameterWithDefault: 6)
// parameterWithDefault est égale à 6
someFunction(parameterSansDefault: 4)
// parameterWithDefault est égale à 12
Placez les paramètres qui n'ont pas de valeurs par défaut au début de la liste des paramètres d'une fonction, avant les paramètres qui ont des valeurs par défaut. Les paramètres qui n'ont pas de valeurs par défaut sont généralement plus importants pour la signification de la fonction - les écrire en premier permet de reconnaître plus facilement que la même fonction est appelée, que des paramètres par défaut soient omis ou non.
Paramètre variadique
Un paramètre variadique accepte zéro ou plusieurs valeurs d'un type spécifié. Vous utilisez un paramètre variadique pour spécifier que le paramètre peut recevoir un nombre variable de valeurs d'entrées lorsque la fonction est appelée. Ecrivez des paramètres variadiques en insérant trois caractères de point ( ...) après le nom du type de paramètre.
Les valeurs passées à un paramètre variadique sont rendues disponibles dans le corps de la fonction sous la forme d'un tableau Array du type approprié.
func arithmeticMean(_ numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
// la moyenne est de 3.0
Paramètre InOut
Les paramètres de fonction sont des constantes par défaut. Tenter de modifier la valeur d'un paramètre de fonction à partir du corps de cette fonction entraîne une erreur de compilation.
Cela signifie que vous ne pouvez pas modifier la valeur d'un paramètre par erreur. Si vous souhaitez qu'une fonction modifie la valeur d'un paramètre et que vous souhaitez que ces modifications persistent une fois l'appel de fonction terminé, définissez ce paramètre comme paramètre inout.
Vous écrivez un paramètre entrée-sortie en plaçant le mot- clé inout juste avant le type d'un paramètre. Un paramètre in-out (entrée-sortie) a une valeur qui est transmise à la fonction, qui est modifiée par la fonction et qui est renvoyée hors de la fonction pour remplacer la valeur d'origine.
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
// Échange les valeurs de a en b, et de b en a
Vous placez une esperluette & directement avant le nom d'une variable lorsque vous la transmettez comme argument à un paramètre inout (entrée-sortie), pour indiquer qu'elle peut être modifiée par la fonction.
var someInt = 3, anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt = \(someInt), et anotherInt = \(anotherInt)")
// someInt = 107, et anotherInt= 3
Types de fonctions
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
}
Le type de cette fonction est : (Int, Int) -> Int, qui se traduit par : "Une fonction avec deux paramètres de type Int et qui renvoie une valeur de type Int"
func printHelloWorld() {
print("hello, world")
}
Le type de cette fonction est () -> Void, ou "une fonction qui n'a pas de paramètre et qui renvoie Void."
Vous utilisez des types de fonctions comme tous les autres types dans Swift. Par exemple, vous pouvez définir une constante ou une variable comme étant un type de fonction et affecter une fonction appropriée à cette variable :
var mathFunction: (Int, Int) -> Int = addTwoInts
Définissez une variable appelée mathFunction, qui a un type de fonction qui prend deux valeurs Int et renvoie une valeur Int. Définissez cette nouvelle variable pour faire référence à la fonction appelée addTwoInts.
Vous pouvez maintenant appeler la fonction attribuée avec le nom mathFunction.
print("Resultat : \(mathFunction(2, 3))")
// "Resultat : 5"
Comme pour tout autre type, vous pouvez laisser à Swift le soin de déduire le type de fonction lorsque vous affectez une fonction à une constante ou une variable :
let anotherMathFunction = addTwoInts
// anotherMathFunction est supposé être de type (Int, Int) -> Int
Types de fonction en tant que types de paramètres
On peut utiliser un type de fonction tel qu'un type de paramètre pour une autre fonction :
func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
print("Resultat: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// "Resultat: 8"
Cet exemple définit une fonction appelée printMathResult(_:_:_:), qui a trois paramètres. Le premier paramètre est appelé mathFunction, et est de type (Int, Int) -> Int. Vous pouvez passer n'importe quelle fonction de ce type comme argument pour ce premier paramètre.
Les deuxième et troisième paramètres sont appelés a et b, et sont tous deux de type Int. Celles-ci sont utilisées comme les deux valeurs d'entrée pour la fonction mathématique fournie.
Types de fonction comme types de retour
Vous pouvez utiliser un type de fonction comme type de retour d'une autre fonction. Pour ce faire, écrivez un type de fonction complet immédiatement après la flèche de retour ( ->) de la fonction renvoyée.
L'exemple suivant définit deux fonctions simples appelées stepForward(_:) et stepBackward(_:). La fonction stepForward(_:) renvoie une valeur un de plus que sa valeur d'entrée et la fonction stepBackward(_:) renvoie une valeur de moins un que sa valeur d'entrée. Les deux fonctions ont un type de (Int) -> Int
// Incrémentation : +1
func stepForward(_ input: Int) -> Int {
return input + 1
}
// Décrémentation : -1
func stepBackward(_ input: Int) -> Int {
return input - 1
}
La fonction chooseStepFunction(backward:) a pour type de retour (Int) -> Int . La fonction chooseStepFunction(backward:) renvoie la fonction stepForward(_:) ou la fonction stepBackward(_:) basée sur un paramètre booléen appelé backward.
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
return backward ? stepBackward : stepForward
}
Vous pouvez maintenant utiliser chooseStepFunction(backward:) pour obtenir une fonction qui va avancer dans un sens ou dans l'autre :
var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero fait maintenant référence à la fonction stepBackward()
L'exemple ci-dessus détermine si une étape positive ou négative est nécessaire pour que currentValue se rapproche progressivement de zéro. currentValue a une valeur initiale de 3.
print("Compte à rebours :")
// Compte à rebours :
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// 3...
// 2...
// 1...
// zero!
Fonction imbriquée ou nested
Toutes les fonctions que vous avez rencontré précédemment sont des fonctions globales, qui sont définies à une portée globale. Vous pouvez également définir des fonctions à l'intérieur du corps d'autres fonctions, appelées fonctions imbriquées ou nested .
Les fonctions imbriquées sont cachées du monde extérieur par défaut, mais peuvent toujours être appelées et utilisées par leur fonction englobante. Une fonction englobante peut également renvoyer l'une de ses fonctions imbriquées pour permettre à la fonction imbriquée d'être utilisée dans une autre portée.
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
func stepForward(input: Int) -> Int { return input + 1 }
func stepBackward(input: Int) -> Int { return input - 1 }
return backward ? stepBackward : stepForward
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero = fonction imbriquée stepForward()
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// -4..., -3..., -2..., -1..., zero!