Historique de la question : L'effacement de type (type erasure) est un patron qui est apparu en Swift comme une réponse aux limitations des protocoles avec des types associés ou des exigences Self. Un protocole ne peut pas être utilisé comme type directement sans effacement de type, s'il contient des types associés, car le compilateur ne connaît pas la mise en œuvre concrète. Cela est souvent rencontré lors de la création de conteneurs de données, de collections, de flux, où l'abstraction est importante.
Problème : Si nous avons un protocole avec un associatedtype, par exemple :
protocol Animal { associatedtype Food func eat(_ food: Food) }
il est impossible de déclarer une variable de type Animal. Nous avons besoin d'un type "effaçant" qui permet d'accéder à différents types concrets via l'abstraction :
let zoo: [any Animal] // Erreur de compilation
Solution : L'effacement de type est réalisé à l'aide d'enveloppes (par exemple, le patron Box ou struct AnyXxx), fournissant une interface unique tout en cachant les détails du type réel :
struct AnyAnimal<F>: Animal { private let _eat: (F) -> Void init<A: Animal>(_ base: A) where A.Food == F { _eat = base.eat } func eat(_ food: F) { _eat(food) } }
Maintenant, nous pouvons conserver différentes implémentations d'Animal avec le même Food :
let animals: [AnyAnimal<Grass>] = [AnyAnimal(Cow()), AnyAnimal(Sheep())]
Caractéristiques clés :
Peut-on utiliser un protocole avec un associatedtype sans effacement de type comme type de propriété ou de tableau ?
Non, ce n'est pas possible. Le compilateur exige la spécification de tous les types associés. Par exemple, l'enregistrement suivant générera une erreur :
let array: [Animal] // Erreur : 'Animal' ne peut être utilisé qu'en tant que contrainte générique
L'effacement de type peut-il remplacer l'héritage ?
Non, l'effacement de type n'est pas un remplacement complet de l'héritage. Il résout le problème d'abstraction pour les protocoles avec associatedtype, tandis que l'héritage est utilisé pour implémenter une logique commune et réutiliser du code entre les classes.
Doit-on implémenter tous les méthodes et propriétés du protocole à l'intérieur de l'enveloppe d'effacement de type ?
Oui, absolument. L'effacement de type fonctionne uniquement si l'enveloppe réplique complètement l'interface externe du protocole, sinon une partie de la fonctionnalité sera inaccessible.
Dans un projet en production, tout le travail avec les sources de données est basé sur l'effacement de type, même lorsqu'il n'y a pas besoin d'associatedtype. Le code devient difficile à maintenir, les nouveaux développeurs se perdent.
Avantages :
Inconvénients :
L'effacement de type est appliqué uniquement pour l'abstraction de la source de données, qui encapsule différentes stratégies de chargement (réseau, local), chacune avec ses propres types. Pour le reste, le code est transparent.
Avantages :
Inconvénients :