Les generics (types génériques) permettent de définir des fonctions et des types flexibles et réutilisables. La caractéristique clé de Swift est le maintien de la sécurité de type : le compilateur vérifie l'utilisation de types spécifiques lors de la compilation. Les types génériques peuvent être restreints par des conditions where, l'héritage de protocoles et leur combinaison.
Exemple de code :
func swapValues<T>(_ a: inout T, _ b: inout T) { let temp = a a = b b = temp } protocol Drawable { func draw() } func drawAll<T: Drawable>(_ items: [T]) { for item in items { item.draw() } } // Restriction par protocole et condition where func compareValues<T: Equatable>(_ a: T, _ b: T) -> Bool { return a == b }
Les fonctions génériques peuvent-elles être surchargées avec des fonctions ordinaires ? Comment le compilateur choisit-il la bonne implémentation ?
Réponse : Oui, les fonctions génériques peuvent être surchargées avec des fonctions ordinaires et d'autres fonctions génériques. Le compilateur essaie de choisir l'implémentation la plus spécifique. Exemple :
func printValue(_ value: Int) { print("Int: \(value)") } func printValue<T>(_ value: T) { print("Générique: \(value)") } printValue(5) // Int: 5 printValue("Swift") // Générique: Swift
Histoire
L'équipe a écrit une extension générique de tableau pour rechercher un indice, en oubliant de restreindre le type via Equatable. Cela a conduit à une erreur de compilation lors de la tentative d'application de l'extension sur un tableau avec des éléments non Equatable.
Histoire
Dans le projet, ils ont essayé de réaliser un cache pour des objets génériques sans restriction de type. En conséquence, lors de la tentative de downcast à l'exécution, des crashs se produisaient — une utilisation réellement sécurisée aurait pu être atteinte par des protocoles avec des types associés et des contraintes.
Histoire
Les développeurs ont mis en œuvre une classe générique, mais lors de l'héritage et de la redéfinition, ils ont oublié la nécessité d'indiquer le paramètre générique complet de l'héritier. En raison de cela, le code ne compilait pas et une refonte complète de la hiérarchie des types était nécessaire.