Generic (generiek programmeren) — is een Swift-mechanisme waarmee je typen en functies kunt schrijven met een geparametriseerd type
Belangrijkste punten
Generic (generiek type) — is een syntactische constructie in Swift die het schrijven van flexibele, herbruikbare code met type-parametrisatie mogelijk maakt. In plaats van een concreet type wordt een placeholder in punthaken geschreven — meestal
Zonder generic zouden er aparte functies voor elk type moeten worden geschreven: swapInts, swapStrings, swapDates. De generic functie swap vervangt alle drie varianten met een declaratie. Dit vermindert duplicatie, verhoogt de leesbaarheid en verlaagt de kans op fouten bij het kopiëren van code.
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)
De Swift-compiler genereert gespecialiseerde code voor elk concreet gebruik van generic. Dit betekent dat de generic functie swapValues
Generic functies — zijn functies die een of meerdere type-parameters accepteren. Type-parameters worden na de functienaam in punthaken aangegeven:
Een functie kan meerdere generic-parameters hebben. Bijvoorbeeld, de functie findKey
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
}
De beperkingen K: Hashable en where V: Equatable garanderen dat findKey alleen kan worden aangeroepen met een woordenboek waarvan de sleutels hashbaar zijn en de waarden vergelijkbaar. Dergelijke beperkingen zijn geen bureaucratie, maar noodzaak: zonder Hashable kan het zoeken op sleutel niet worden geïndexeerd, zonder Equatable kan value niet worden vergeleken met dictValue.
where — is een Swift-zoekwoord dat extra beperkingen oplegt aan generic-parameters. In tegenstelling tot het eenvoudig specificeren van een protocol in punthaken (
De where-clausule wordt geschreven na de handtekening van de functie of het type, voor de openingsaccolade. In where kan worden gespecificeerd dat T: Comparable & Hashable (tegelijkertijd twee protocollen), of dat T.U == Int (concretisering van associated type).
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
}
}
De extensie met where voegt methoden alleen toe voor die typen die aan de voorwaarde voldoen. Container
Associated Types (geassocieerde typen) — is een manier om een protocol generiek te maken zonder het concrete type in de declaratiefase te specificeren. In plaats van
Met where kunnen relaties worden gelegd tussen associated types van verschillende protocollen. Bijvoorbeeld, kan worden vereist dat Item van het ene protocol overeenkomt met Iterator.Element van een ander. Dit garandeert typecompatibiliteit op compilatieniveau.
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 concretiseert Element als Int met behulp van typealias. De compiler controleert of aan alle vereisten van het protocol met dit type wordt voldaan. Zonder associated types zou StackProtocol
Generic extensies maken het mogelijk methoden toe te voegen aan een generic type met extra beperkingen. Dit is het patroon van „conditionele conformiteit”, waarbij het type alleen onder bepaalde voorwaarden functionaliteit krijgt. Subscripts kunnen ook generic zijn.
Een subscript kan generiek zijn: het accepteert generic-parameters in punthaken. Dit is handig voor veilige toegang tot collecties met een willekeurige index, wanneer de index van verschillende typen kan zijn.
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] }
}
}
Zo'n constructie geeft krachtige compositie: de methode sum verschijnt alleen bij numerieke arrays, en het subscript met willekeurige indices werkt met elke reeks van gehele indices. De compiler beheert zelf de zichtbaarheid van deze leden op basis van where-voorwaarden.
Fouten bij het gebruik van generic zijn vaak gerelateerd aan onjuiste beperkingen of een poging om generic te gebruiken waar een concreet type nodig is. Laten we drie veelvoorkomende scenario's bekijken waar ontwikkelaars mee te maken krijgen.
Het toevoegen van generic-parameters waar een concreet type voldoende is — is een antipatroon. Als een functie altijd met String werkt, hoef je er geen
Het aanroepen van een methode op een generic-parameter zonder te specificeren dat de methode bestaat — is een fout.
// ❌ 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 }
De fout is begrijpelijk: generic
Veelgestelde vragen
Generic — is een manier om code te schrijven die met elk type werkt, zonder dezelfde logica te dupliceren voor Int, String en andere typen. In plaats van een concreet type wordt een placeholder
Generic behoudt informatie over het concrete type in de compilatiefase, waardoor de compiler typen kan controleren en geoptimaliseerde code kan genereren. Any — is type-wissing: elke waarde kan worden doorgegeven, maar het type gaat verloren en conversie (as?) is vereist.
Gebruik de syntax T: SomeProtocol in punthaken of een aparte clausule where T: SomeProtocol. Beperkingen garanderen dat de generic-parameter bepaalde methoden en eigenschappen ondersteunt.
Associated Type (associatedtype) — is een placeholder voor een type binnen een protocol. Het protocol specificeert geen concreet type, maar declareert een associatedtype dat wordt geconcretiseerd in de implementatie: Array heeft Element, Dictionary — Key en Value.
Swift compileert generic-code naar gespecialiseerde versies voor elk concreet type. In de praktijk is een generic functie voor Int niet langzamer dan een handgeschreven functie voor Int. Er is geen overhead voor abstractie.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook