Generic — l’essence des types génériques et des paramètres T

Auteur : IT Sectr Publié le : 2026-06-18 Temps de lecture : 10 min

Generic (programmation générique) — est un mécanisme de Swift permettant d’écrire des types et des fonctions avec un type paramétré . Au lieu de dupliquer le code pour Int, String et les structures personnalisées, le développeur crée une solution générique unique qui fonctionne avec n’importe quel type, tout en maintenant un typage strict. Le compilateur substitue le type concret au point d’utilisation, garantissant la sécurité sans perte de performance. Selon Swift Book, 2025, les paramètres génériques sont l’une des fonctionnalités clés du langage, constituant la base de la bibliothèque standard et de SwiftUI.

Points Clés

  • Generic — mécanisme de programmation générique avec des paramètres de type
  • Fonctions avec paramètres génériques fonctionnent avec tout type sans duplication de code
  • Contraintes where limitent la portée des génériques aux types satisfaisant des conditions
  • Associated Types dans les protocoles permettent aux protocoles d’être génériques
  • Le compilateur génère du code spécialisé pour chaque type concret

Qu’est-ce que Generic en Swift ?

Generic (type générique) — est une construction syntaxique de Swift qui permet d’écrire du code flexible et réutilisable avec paramétrage de type. Au lieu d’un type concret, un espace réservé est écrit entre crochets angulaires — généralement , mais n’importe quel nom peut être utilisé. Les génériques constituent la base de SwiftUI (View, some View), de la bibliothèque standard (Array, Optional) et de Combine.

Pourquoi les génériques sont nécessaires

Sans génériques, il faudrait écrire des fonctions séparées pour chaque type : swapInts, swapStrings, swapDates. Une fonction générique swap remplace les trois variantes par une seule déclaration. Cela réduit la duplication, améliore la lisibilité et diminue le risque d’erreurs lors de la copie de code.

swift
func swapValues<T>(_ a: inout T, _ b: inout T) {
    let temp = a
    a = b
    b = temp
}

var x = 10
var y = 20
swapValues(&x, &y)

Le compilateur Swift génère du code spécialisé pour chaque utilisation concrète d’un générique. Cela signifie que la fonction générique swapValues n’a pas de surcharge par rapport à une fonction écrite à la main pour Int. Swift n’utilise pas l’effacement de type comme Java — les génériques existent à la fois à la compilation et à l’exécution (bien que l’optimisation puisse les spécialiser).

Fonctions Génériques avec Paramètre T

Fonctions génériques sont des fonctions qui acceptent un ou plusieurs paramètres de type. Les paramètres de type sont spécifiés après le nom de la fonction entre crochets angulaires : . Ils peuvent être utilisés dans la signature : type d’argument, type de retour et à l’intérieur du corps de la fonction.

Paramètres de Type Multiples

Une fonction peut avoir plusieurs paramètres génériques. Par exemple, la fonction findKey prend un dictionnaire avec des clés K et des valeurs V. Chaque paramètre de type est unique et peut être utilisé dans des contraintes.

swift
func findKey<K: Hashable, V>(
    for value: V,
    in dictionary: [K: V]
) -> K? where V: Equatable {
    for (key, dictValue) in dictionary {
        if dictValue == value {
            return key
        }
    }
    return nil
}

Les contraintes K: Hashable et where V: Equatable garantissent que findKey ne peut être appelée qu’avec un dictionnaire dont les clés sont hashable et les valeurs equatable. Ces contraintes ne sont pas de la bureaucratie mais une nécessité : sans Hashable, on ne peut pas indexer une recherche par clé, sans Equatable, on ne peut pas comparer value avec dictValue.

Contraintes de Type avec where

where — est un mot-clé de Swift qui impose des contraintes supplémentaires aux paramètres génériques. Contrairement à la simple spécification d’un protocole entre crochets angulaires (), where permet d’exprimer des conditions plus complexes : conformité à plusieurs protocoles, relations entre paramètres de type et raffinement des associated types.

Syntaxe de where

La clause where est écrite après la signature de la fonction ou du type, avant l’accolade ouvrante. Dans where, vous pouvez spécifier que T: Comparable & Hashable (conforme à deux protocoles simultanément), ou que T.U == Int (concrétiser un associated type).

swift
protocol Container {
    associatedtype Item
    mutating func append(_ item: Item)
    var count: Int { get }
}

extension Container where Item: Comparable {
    func isSorted() -> Bool {
        // Implementation available only if Item: Comparable
        return true
    }
}

L’extension avec where ajoute des méthodes uniquement pour les types qui satisfont la condition. Container obtiendra la méthode isSorted, tandis que Container ne l’obtiendra pas, car Any n’est pas Comparable. C’est un mécanisme puissant de fonctionnalité conditionnelle.

Associated Types dans les Protocoles

Associated Types (types associés) — sont une façon de rendre un protocole générique sans spécifier de type concret au moment de la déclaration. Au lieu de , le protocole déclare un associatedtype, qui est concrétisé dans l’implémentation. Ceci est particulièrement important pour les collections : le protocole Sequence ne sait pas quels éléments la séquence contiendra.

Liaison des Associated Types avec where

En utilisant where, vous pouvez établir des relations entre les associated types de différents protocoles. Par exemple, vous pouvez exiger que l’Item d’un protocole corresponde à Iterator.Element d’un autre. Cela garantit la compatibilité des types au niveau du compilateur.

swift
protocol StackProtocol {
    associatedtype Element
    mutating func push(_ item: Element)
    mutating func pop() -> Element?
}

struct IntStack: StackProtocol {
    typealias Element = Int
    private var items: [Int] = []
    
    mutating func push(_ item: Int) { items.append(item) }
    mutating func pop() -> Int? { items.popLast() }
}

IntStack concrétise Element comme Int en utilisant typealias. Le compilateur vérifie que toutes les exigences du protocole sont remplies avec ce type. Sans associated types, il faudrait écrire StackProtocol avec un protocole générique, mais Swift utilise les associated types pour la cohérence avec les ponts Objective-C et une meilleure lisibilité.

Generic dans les Extensions et les Subscripts

Extensions génériques permettent d’ajouter des méthodes à un type générique avec des contraintes supplémentaires. C’est le modèle de « conformité conditionnelle », où un type obtient des fonctionnalités seulement sous certaines conditions. Les subscripts peuvent également être génériques.

Subscript Générique

Un subscript peut être générique : il accepte des paramètres génériques entre crochets angulaires. Ceci est utile pour un accès sécurisé aux collections avec des index arbitraires, où l’index peut être de différents types.

swift
extension Array where Element: Numeric {
    func sum() -> Element {
        return reduce(0, +)
    }
}

extension Array {
    subscript<Indices: Sequence>(indices: Indices) -> [Element]
        where Indices.Element == Int {
        return indices.map { self[$0] }
    }
}

Cette construction offre une composition puissante : la méthode sum apparaît uniquement sur les tableaux numériques, et le subscript avec des index arbitraires fonctionne avec toute séquence d’index entiers. Le compilateur gère la visibilité de ces membres en fonction des conditions where.

Erreurs Courantes avec les Génériques

Erreurs lors de l’utilisation des génériques sont souvent liées à des contraintes incorrectes ou à la tentative d’utiliser des génériques là où un type concret est nécessaire. Examinons trois scénarios courants rencontrés par les développeurs.

Paramétrage Excessif

Ajouter des paramètres génériques là où un type concret suffit est un anti-modèle. Si une fonction travaille toujours avec String, il n’est pas nécessaire de la rendre . Cela complexifie le code sans bénéfice. Les génériques sont justifiés lorsque le type varie réellement, pas pour une « flexibilité future » abstraite.

Absence de Contrainte where

Appeler une méthode sur un paramètre générique sans spécifier que la méthode existe est une erreur. ne peut pas appeler .count si T: Collection n’est pas spécifié. Ajoutez toujours des contraintes aux paramètres de type, sinon le compilateur rejettera le code.

swift
// ❌ Error: value has no count method
func countElements<T>(value: T) -> Int { value.count }

// ✅ Works: T: Collection guarantees count exists
func countElements<T: Collection>(value: T) -> Int { value.count }

L’erreur est claire : le générique peut être n’importe quel type, et le compilateur ne sait pas s’il a count. La contrainte Collection résout le problème. De même pour Equatable, Hashable, Numeric — spécifiez toujours le protocole si vous prévoyez d’appeler des méthodes ou des opérateurs sur le paramètre générique.

Questions Fréquentes

Qu’est-ce que Generic en Swift en termes simples ?

Generic est une façon d’écrire du code qui fonctionne avec n’importe quel type, sans dupliquer la même logique pour Int, String et d’autres types. Au lieu d’un type concret, un espace réservé est utilisé, qui est remplacé par le type réel au point d’utilisation.

En quoi Generic diffère-t-il de Any ?

Generic préserve les informations sur le type concret au moment de la compilation, permettant au compilateur de vérifier les types et de générer du code optimisé. Any est un effacement de type : n’importe quelle valeur peut être passée, mais le type est perdu, et un cast (as?) est nécessaire.

Comment contraindre un Generic avec un protocole ?

Utilisez la syntaxe T: SomeProtocol entre crochets angulaires ou une clause where séparée where T: SomeProtocol. Les contraintes garantissent que le paramètre générique prend en charge des méthodes et propriétés spécifiques.

Qu’est-ce qu’un Associated Type dans un protocole ?

Associated Type (associatedtype) est un espace réservé pour un type à l’intérieur d’un protocole. Le protocole ne spécifie pas un type concret mais déclare un associatedtype, qui est concrétisé dans l’implémentation : Array a Element, Dictionary a Key et Value.

Les génériques sont-ils plus rapides ou plus lents que les types concrets ?

Swift compile le code générique en versions spécialisées pour chaque type concret. En pratique, une fonction générique pour Int n’est pas plus lente qu’une fonction écrite à la main pour Int. Il n’y a pas de surcharge d’abstraction.

Résumé

  • Generic — mécanisme de programmation générique avec paramètre de type
  • Fonctions et types avec paramètres génériques remplacent plusieurs implémentations dupliquées
  • Contraintes where limitent la portée des génériques aux conditions nécessaires
  • Associated Types permettent aux protocoles d’être génériques sans concrétisation à la déclaration
  • Extensions avec where ajoutent des fonctionnalités seulement lorsque les conditions sont remplies
  • Le compilateur génère du code spécialisé — les génériques n’ajoutent pas de surcharge
  • Paramétrage excessif est un anti-modèle — utilisez les génériques seulement lorsque le type varie réellement

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi