Generics in Swift: vollständige Anleitung mit Codebeispielen

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Generics in Swift: Warum sie wichtig sind und wie man sie in der Praxis verwendet



Generics (generische Programmierung) sind eine der leistungsstärksten und grundlegendsten Funktionen der Sprache Swift. Sie ermöglichen es, flexiblen, typsicheren und wiederverwendbaren Code zu schreiben und Duplikate zu vermeiden. Wenn Sie jemals Array<Int>, Dictionary<String, Any> oder Optional<T> verwendet haben, sind Sie bereits mit Generics in Berührung gekommen. In diesem Artikel werden wir uns ansehen, warum sie wichtig sind, wie man sie richtig anwendet und praktische Beispiele für die iOS/macOS-Entwicklung betrachten.



Warum sind Generics in Swift wichtig?



Das Hauptproblem, das Generics lösen, ist die Notwendigkeit, denselben Code für verschiedene Datentypen zu schreiben. Ohne sie müssten Sie separate Funktionen für die Arbeit mit Int, String, Double und benutzerdefinierten Strukturen erstellen. Dies führt zu Code-Duplikaten, Fehlern und erschwert die Wartung.



Die wichtigsten Vorteile von Generics:

  • Typsicherheit: Der Compiler überprüft die Typen zur Compile-Zeit und verhindert Laufzeitfehler.
  • Code-Wiederverwendung: Eine Funktion oder ein Typ funktioniert mit jedem Datentyp.
  • Leistung: Generics in Swift werden durch Spezialisierung implementiert – der Compiler erzeugt optimierten Code für jeden spezifischen Typ, vergleichbar mit manuellem Schreiben von doppeltem Code.
  • Lesbarkeit und Abstraktion: Der Code wird prägnanter und ausdrucksstärker.


Betrachten wir ein einfaches Beispiel. Angenommen, wir benötigen eine Funktion zum Vertauschen der Werte zweier Variablen. Ohne Generics müsste man so schreiben:



func swapInts(_ a: inout Int, _ b: inout Int) {    let temp = a    a = b    b = temp}

func swapStrings(_ a: inout String, _ b: inout String) { let temp = a a = b b = temp}// ... und so weiter für jeden Typ


Mit Generics wird die Lösung universell:



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

var x = 10var y = 20swapValues(&x, &y) // Funktioniert mit Int

var str1 = "Hello"var str2 = "World"swapValues(&str1, &str2) // Funktioniert mit String


Wie Sie sehen, ist <T> ein Platzhalter für den Typ. Der Compiler leitet den konkreten Typ beim Aufruf der Funktion automatisch ab.



Generische Funktionen und Typen



Generics können nicht nur mit Funktionen, sondern auch mit benutzerdefinierten Typen verwendet werden: Strukturen, Klassen und Aufzählungen.



Generische Funktionen

Neben einfachen Platzhaltern können Sie auch Einschränkungen für den Typ festlegen. Zum Beispiel eine Funktion, die nur mit Typen funktioniert, die das Protokoll Equatable implementieren:



func findIndex<T: Equatable>(of value: T, in array: [T]) -> Int? {    for (index, item) in array.enumerated() {        if item == value {            return index        }    }    return nil}

let numbers = [1, 5, 3, 12]if let index = findIndex(of: 5, in: numbers) { print("Index gefunden: \\(index)") // Gibt aus: Index gefunden: 1}


Die Einschränkung <T: Equatable> stellt sicher, dass für den Typ T der Operator == definiert ist.



Generische Typen (Strukturen und Klassen)

Erstellen wir einen einfachen Stack – eine Datenstruktur, die nach dem LIFO-Prinzip (Last In, First Out) funktioniert:



struct Stack<Element> {    private var items = [Element]()        mutating func push(_ item: Element) {        items.append(item)    }        mutating func pop() -> Element? {        return items.popLast()    }        var top: Element? {        return items.last    }}

var intStack = Stack<Int>()intStack.push(10)intStack.push(20)print(intStack.pop() ?? 0) // 20

var str

Blogs

Buchempfehlungen