Achtergrond van de vraag: Type erasure (typewissen) is een patroon dat in Swift is ontstaan als antwoord op de beperkingen van protocollen met associated type of Self vereisten. Een protocol kan niet rechtstreeks als type worden gebruikt zonder type erasure als het verbonden types bevat, omdat de compiler de specifieke implementatie niet kent. Dit komt vaak voor bij het maken van datacontainers, verzamelingen, stroomlijnen, waar abstractie belangrijk is.
Probleem: Als er een protocol is met associatedtype, bijvoorbeeld:
protocol Animal { associatedtype Food func eat(_ food: Food) }
kun je een variabele van het type Animal niet declareren. We hebben een "wisser wrapper" type nodig dat toegang biedt tot verschillende specifieke types via abstractie:
let zoo: [any Animal] // Compilatiefout
Oplossing: Type erasure wordt geïmplementeerd met behulp van wrappers (bijvoorbeeld het Box-patroon of struct AnyXxx), die een uniforme interface bieden en de details van het werkelijke type verbergen:
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) } }
Nu kunnen verschillende implementaties van Animal met dezelfde Food worden opgeslagen:
let animals: [AnyAnimal<Grass>] = [AnyAnimal(Cow()), AnyAnimal(Sheep())]
Belangrijke kenmerken:
Kan een protocol met associatedtype zonder type erasure worden gebruikt als type van een eigenschap of array?
Nee, dat kan niet. De compiler vereist specificatie van alle verbonden types. Bijvoorbeeld, de volgende notatie zal een fout veroorzaken:
let array: [Animal] // Fout: 'Animal' kan alleen worden gebruikt als een generieke beperking
Kan type erasure overerving vervangen?
Nee, type erasure is geen volledige vervanging voor overerving. Het lost de abstractieprobleem van protocollen met associatedtype op, terwijl overerving wordt gebruikt voor het implementeren van gedeelde logica en hergebruik van code tussen klassen.
Moet ik alle methoden en eigenschappen van het protocol binnen de type erasure wrapper implementeren?
Ja, absoluut. Type erasure werkt alleen als de wrapper volledig de externe interface van het protocol herhaalt, anders zal een deel van de functionaliteit niet beschikbaar zijn.
In een productieproject is al het werk met gegevensbronnen gebaseerd op type erasure, zelfs wanneer er geen behoefte is aan een associatedtype. De code wordt moeilijk te onderhouden, nieuwe ontwikkelaars raken in de war.
Voordelen:
Nadelen:
Type erasure wordt alleen toegepast voor de abstractie van de gegevensbron, die verschillende laadstrategieën encapsuleert (netwerk, lokaal), elk met zijn eigen types. Verder is de code transparant.
Voordelen:
Nadelen: