Generic (programare generică) — este un mecanism Swift care permite scrierea tipurilor și funcțiilor cu un tip parametrizat
Principalele puncte
Generic (tip generic) — este o construcție sintactică Swift care permite scrierea de cod flexibil, reutilizabil cu parametrizare după tip. În locul unui tip concret se scrie un placeholder în paranteze unghiulare — de obicei
Fără generic ar trebui scrise funcții separate pentru fiecare tip: swapInts, swapStrings, swapDates. Funcția generic swap înlocuiește toate cele trei variante cu o singură declarație. Aceasta reduce duplicarea, crește lizibilitatea și scade probabilitatea erorilor la copierea codului.
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)
Compilatorul Swift generează cod specializat pentru fiecare utilizare concretă a generic. Aceasta înseamnă că funcția generic swapValues
Funcțiile generic — sunt funcții care acceptă unul sau mai mulți parametri-tip. Parametrii-tip sunt indicați după numele funcției în paranteze unghiulare:
O funcție poate avea mai mulți parametri generic. De exemplu, funcția 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
}
Constrângerile K: Hashable și where V: Equatable garantează că findKey poate fi apelat doar cu un dicționar ale cărui chei sunt hashingabile și valorile comparabile. Astfel de constrângeri nu sunt birocrație, ci necesitate: fără Hashable nu se poate indexa căutarea după cheie, fără Equatable nu se poate compara value cu dictValue.
where — este un cuvânt cheie Swift care impune constrângeri suplimentare asupra parametrilor generic. Spre deosebire de simpla specificare a protocolului în paranteze unghiulare (
Clauza where se scrie după semnătura funcției sau tipului, înainte de acolada deschisă. În where se poate specifica că T: Comparable & Hashable (simultan două protocoale), sau că T.U == Int (concretizarea 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
}
}
Extensia cu where adaugă metode doar pentru acele tipuri care îndeplinesc condiția. Container
Associated Types (tipuri asociate) — este un mod de a face protocolul generic fără a specifica tipul concret în faza de declarare. În loc de
Cu ajutorul where se pot stabili legături între associated types ale diferitelor protocoale. De exemplu, se poate cere ca Item al unui protocol să coincidă cu Iterator.Element al altuia. Aceasta garantează compatibilitatea tipurilor la nivel de compilare.
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 concretizează Element ca Int, folosind typealias. Compilatorul verifică dacă toate cerințele protocolului sunt îndeplinite cu acest tip. Fără associated types ar trebui scris StackProtocol
Extensiile generic permit adăugarea de metode la un tip generic cu constrângeri suplimentare. Acesta este pattern-ul „conformitate condiționată”, când tipul primește funcționalitate doar în anumite condiții. Subscriptările pot fi și ele generic.
O subscriptare poate fi generică: acceptă parametri generic în paranteze unghiulare. Acest lucru este util pentru acces sigur la colecții cu un index arbitrar, când indexul poate fi de diferite tipuri.
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] }
}
}
O astfel de construcție oferă o compunere puternică: metoda sum apare doar la array-urile numerice, iar subscriptarea cu indici arbitrari funcționează cu orice secvență de indici întregi. Compilatorul însuși gestionează vizibilitatea acestor membri pe baza condițiilor where.
Erorile la utilizarea generic sunt adesea legate de constrângeri incorecte sau încercarea de a folosi generic acolo unde este nevoie de un tip concret. Să analizăm trei scenarii frecvente cu care se confruntă dezvoltatorii.
Adăugarea parametrilor generic acolo unde este suficient un tip concret — este un anti-pattern. Dacă o funcție lucrează întotdeauna cu String, nu este nevoie să o faceți
Apelarea unei metode pe un parametru generic fără a specifica că metoda există — este o eroare.
// ❌ 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 }
Eroarea este de înțeles: generic
Întrebări frecvente
Generic — este un mod de a scrie cod care funcționează cu orice tip, fără a duplica aceeași logică pentru Int, String și alte tipuri. În locul unui tip concret se folosește un placeholder
Generic păstrează informația despre tipul concret în faza de compilare, ceea ce permite compilatorului să verifice tipurile și să genereze cod optimizat. Any — este ștergerea tipului: orice valoare poate fi transmisă, dar tipul se pierde și este necesară conversia (as?).
Utilizați sintaxa T: SomeProtocol în paranteze unghiulare sau o clauză separată where T: SomeProtocol. Constrângerile garantează că parametrul generic suportă anumite metode și proprietăți.
Associated Type (associatedtype) — este un placeholder pentru un tip în interiorul protocolului. Protocolul nu specifică un tip concret, ci declară un associatedtype care este concretizat în implementare: Array are Element, Dictionary — Key și Value.
Swift compilează codul generic în versiuni specializate pentru fiecare tip concret. În practică, o funcție generică pentru Int nu este mai lentă decât o funcție scrisă manual pentru Int. Nu există costuri suplimentare pentru abstractizare.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și