Generics in Swift: Wozu sie dienen und wie man sie verwendet

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

Was sind Generics in Swift und warum werden sie benötigt?



Generics (generische Programmierung) sind eine der leistungsstärksten Funktionen der Swift-Sprache. Sie ermöglichen es Ihnen, flexiblen, wiederverwendbaren Code zu schreiben, der mit jedem Datentyp funktioniert und gleichzeitig eine starke Typsicherheit gewährleistet. Anstatt separate Funktionen oder Strukturen für Int, String, Double und andere Typen zu erstellen, schreiben Sie ein einheitliches Code-Stück, das sich zur Compile-Zeit an den spezifischen Typ anpasst.



Stellen Sie sich vor, Sie müssen eine Funktion schreiben, die zwei Werte vertauscht. Ohne Generics müssten Sie für jeden Typ Überladungen erstellen:



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}


Mit Generics wird dies in einer Zeile erledigt:



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

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

var str1 = "Hallo", str2 = "Welt"swapValues(&str1, &str2) // funktioniert mit String


Hauptvorteile von Generics



  • Typsicherheit: der Compiler prüft Typen zur Compile-Zeit und eliminiert Laufzeitfehler
  • Code-Wiederverwendung: einmal geschriebener Code funktioniert mit beliebigen Typen
  • Leistung: Generics werden in Swift auf Compiler-Ebene implementiert, ohne Geschwindigkeitseinbußen
  • Lesbarkeit: reduziert Code-Duplizierung und macht den Code prägnanter


Generische Funktionen und Typparameter



Eine generische Funktion wird mit spitzen Klammern <> deklariert, in denen ein Typparameter angegeben wird (normalerweise mit dem Buchstaben T bezeichnet, es können aber beliebige Namen verwendet werden). Der Typparameter fungiert als Platzhalter, der beim Aufruf der Funktion durch den tatsächlichen Typ ersetzt wird.



Beispiel: Suchen eines Elements in einem Array



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

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

let names = ["Anna", "Boris", "Viktor"]if let index = findIndex(of: "Boris", in: names) { print("Index des Namens Boris: \\(index)") // Index des Namens Boris: 1}


Beachten Sie die Einschränkung T: Equatable. Dies ist eine Typeinschränkung — wir fordern, dass der Typ T das Equatable-Protokoll unterstützt, da sonst die Vergleichsoperation == unmöglich wäre.



Generische Typen: Strukturen, Klassen und Enumerationen



Generics funktionieren nicht nur mit Funktionen, sondern auch mit benutzerdefinierten Typen. Dies ermöglicht die Erstellung universeller Datencontainer.



Erstellen eines generischen Stapels



Ein klassisches Beispiel ist die Datenstruktur Stack (Stapel), die mit jedem Typ funktioniert:



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

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

var stringStack = Stack<String>()stringStack.push("Swift")stringStack.push("Generics")print(stringStack.pop() ?? "") // Generics


Generische Enumerationen



Enumerationen können ebenfalls

Blogs

Buchempfehlungen