Programmation fonctionnelle en Swift : des fermetures à la composition
Swift a été conçu dès le départ comme un langage multiparadigme. Il prend en charge la programmation orientée objet, orientée protocole et fonctionnelle. L'approche fonctionnelle aide à écrire un code plus prévisible, testable et thread-safe. Dans cet article, nous allons détailler les concepts clés de la programmation fonctionnelle en Swift avec des exemples pratiques.
1. Fonctions pures et immutabilité
La base du style fonctionnel repose sur les fonctions pures. Une telle fonction retourne toujours le même résultat pour les mêmes arguments et n'a pas d'effets secondaires (elle ne modifie pas l'état externe).
// Fonction impure — modifie une variable externevar total = 0func addToTotal(_ value: Int) -> Int { total += value return total}
// Fonction pure — uniquement un calculfunc add(_ a: Int, _ b: Int) -> Int { return a + b}L'immutabilité est obtenue via let et les structures avec sémantique de valeur. Au lieu de modifier un tableau, nous en créons un nouveau :
let numbers = [1, 2, 3, 4, 5]// Au lieu de var et append :let newNumbers = numbers + [6] // [1, 2, 3, 4, 5, 6]2. Fermetures (Closures) comme blocs de construction
Les fermetures en Swift sont des fonctions anonymes qui peuvent capturer des variables du contexte environnant. Elles sont des « citoyens de première classe » : on peut les passer comme paramètres et les retourner depuis des fonctions.
// Fermeture simplelet multiply: (Int, Int) -> Int = { $0 * $1 }let result = multiply(3, 4) // 12
// Fermeture avec capture de contextevar counter = 0let increment = { counter += 1 }increment() // counter = 1increment() // counter = 2Les fermetures sont activement utilisées dans les méthodes d'ordre supérieur, comme sorted :
let names = ["Иван", "Анна", "Борис", "Елена"]let sorted = names.sorted { $0.localizedStandardCompare($1) == .orderedAscending }print(sorted) // ["Анна", "Борис", "Елена", "Иван"]3. Méthodes d'ordre supérieur : map, filter, reduce
Ce sont les « chevaux de bataille » du style fonctionnel en Swift. Elles permettent de traiter des collections sans boucles explicites ni mutation.
map
Transforme chaque élément d'une collection :
let prices = [100, 200, 300]let withTax = prices.map { $0 * 1.2 }print(withTax) // [120.0, 240.0, 360.0]
// Exemple concret : extraire les noms d'un tableau de modèlesstruct User { let name: String let age: Int}let users = [User(name: "Алексей", age: 30), User(name: "Мария", age: 25)]let userNames = users.map { $0.name }print(userNames) // ["Алексей", "Мария"]filter
Sélectionne les éléments selon une condition :
let numbers = [1, 2, 3, 4, 5, 6]let evenNumbers = numbers.filter { $0 % 2 == 0 }print(evenNumbers) // [2, 4, 6]
// Filtrage des utilisateurs de plus de 18 anslet adults = users.filter { $0.age >= 18 }reduce
Réduit une collection à une seule valeur :
let sum = numbers.reduce(0, +) // 21// Construire une chaîne à partir d'un tableaulet words = ["Функциональное", "программирование", "Swift"]let sentence = words.reduce("") { $0.isEmpty ? $1 : $0 + " " + $1 }print(sentence) // "Функциональное программирование Swift"Combinaison de méthodes
Le plus intéressant, ce sont les chaînes d'appels :
let transactions = [250, -50, 100, -200, 300, -100]let balance = transactions .filter { $0 > 0 } // uniquement les revenus .map { $0 * 0.87 } // déduction de l'impôt de 13% .reduce(0, +) // sommeprint(balance) // 565.54. Composition de fonctions et curryfication
La composition permet de combiner plusieurs fonctions en une seule. Swift ne dispose pas d'opérateur de composition intégré, mais