English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Swift-Generische

Swift bietet Generics, um flexible und wiederverwendbare Funktionen und Typen zu schreiben.

Die Swift-Bibliothek ist durch generische Code konstruiert.

Die Array- und Dictionary-Typen in Swift sind generische Sammlungen.

Sie können eine Int-Array, eine String-Array oder sogar eine Array von beliebigen anderen Swift-Datentypen erstellen.

Nachfolgender Beispiel ist eine nicht generische Funktion exchange, die zwei Int-Werte austauscht:

Online-Beispiel

// Definieren Sie eine Funktion, um zwei Variablen auszutauschen
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}
 
var numb1 = 100
var numb2 = 200
 
print("Austausch vor Daten: \(numb1) und \(numb2)")
swapTwoInts(&numb1, \&numb2)
print("Daten nach dem Austausch: \(numb1) und \(numb2)")

Die Ausgabe des obigen Programms ist:

Daten vor dem Austausch: 100 und 200
Daten nach dem Austausch: 200 und 100

Dieser Beispiel ist nur für den Austausch von Variablen des Int-Typs geeignet. Wenn Sie zwei String-Werte oder Double-Werte austauschen möchten, müssen Sie eine entsprechende Funktion wie swapTwoStrings(_:_:) oder swapTwoDoubles(_:_:) neu schreiben, wie folgt:

String- und Double-Wert-Austauschfunktion

func swapTwoStrings(_ a: inout String, _ b: inout String) {
    let temporaryA = a
    a = b
    b = temporaryA
}
 
func swapTwoDoubles(_ a: inout Double, _ b: inout Double) {
    let temporaryA = a
    a = b
    b = temporaryA
}

Wie aus dem obigen Code hervorgeht, sind die Funktionscodeabschnitte identisch, nur die Typen unterscheiden sich, in diesem Fall können wir Generikity verwenden, um die Codekopie zu vermeiden.

Generische Typen verwenden Platzhalternamen (hier verwendet T als Platzhalter) anstelle echter Typnamen (z.B. Int, String oder Double).

func swapTwoValues<T>(_ a: inout T, _ b: inout T)

swapTwoValues gefolgt von dem Platzhalternamen (T), eingeklemmt in eckige Klammern (<T>)。Diese eckigen Klammern erzählen Swift, dass T ein Platzhalter für einen Typnamen in der Definition der Funktion swapTwoValues(_:_:) ist, daher sucht Swift nicht nach einem tatsächlichen Typnamen namens T.

Ein Beispiel für eine generische Funktion exchange, die zwei Int- und String-Werte austauscht:

Online-Beispiel

// Definieren Sie eine Funktion, um zwei Variablen auszutauschen
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
    let temporaryA = a
    a = b
    b = temporaryA
}
 
var numb1 = 100
var numb2 = 200
 
print("Daten vor dem Austausch: \(numb1) und \(numb2)")
swapTwoValues(&numb1, \&numb2)
print("Daten nach dem Austausch: \(numb1) und \(numb2)")
 
var str1 = "A"
var str2 = "B"
 
print("Daten vor dem Austausch: \(str1) und \(str2)")
swapTwoValues(&str1, \&str2)
print("Daten nach dem Austausch: \(str1) und \(str2)")

Die Ausgabe des obigen Programms ist:

Daten vor dem Austausch:  100 und 200
Daten nach dem Austausch: 200 und 100
Daten vor dem Austausch: A und B
Daten nach dem Austausch: B und A

Generische Typen

Swift ermöglicht es Ihnen, Ihre eigenen generischen Typen zu definieren.

Benutzerdefinierte Klassen, Strukturen und Enumerationen wirken sich auf alle Typen aus, wie die Verwendung von Array und Dictionary.

Nun schreiben wir einen generischen Sammlungstyp namens Stack (Stack) und er erlaubt es, neue Elemente nur am Ende der Sammlung hinzuzufügen (eingeordnet), und kann Elemente auch nur am Ende entfernen (ausgeordnet).

Die Analyse von links nach rechts im Bild ist wie folgt:

  • Es gibt drei Werte im Stapel.

  • Der vierte Wert wird auf den obersten Platz im Stapel gelegt.

  • Es gibt jetzt vier Werte im Stapel, der letzte hinzugefügte Wert ist oben.

  • Der oberste Wert im Stapel wird entfernt, oder auch als Ausgabe aus dem Stapel bezeichnet.

  • Nachdem ein Wert entfernt wurde, gibt es jetzt nur noch drei Werte im Stapel.

Nachfolgend ist ein Beispiel für eine nicht generische Stapelversion, ein Beispiel für einen Stapel vom Typ Int:

Int Stapel

struct IntStack {
    var items = [Int]()
    mutating func push(_ item: Int) {
        items.append(item)
    }
    mutating func pop() -> Int {
        return items.removeLast()
    }
}

Diese Struktur verwendet eine als items bezeichnete Array-Attribute, um Werte zu speichern. Stack bietet zwei Methoden: push(_) und pop(), um Werte in den Stapel einzufügen und Werte aus dem Stapel zu entfernen. Diese Methoden sind als mutating markiert, da sie das Array items der Struktur ändern müssen.

Die obige Struktur IntStack kann nur für Int-Typen verwendet werden. Allerdings kann eine generische Stack-Struktur definiert werden, um Werte beliebiger Typen zu verarbeiten.

Hier ist die generische Version desselben Codes:

Generischer Stapel

struct Stack<Element> {
    var items = [Element]()
    mutating func push(_ item: Element) {
        items.append(item)
    }
    mutating func pop() -> Element {
        return items.removeLast()
    }
}
 
var stackOfStrings = Stack<String>()
print("Einzelelemente in den String in den Stapel einlegen:")
stackOfStrings.push("google")
stackOfStrings.push("w3codebox)
print(stackOfStrings.items);
 
let deletetos = stackOfStrings.pop()
print("Element aus dem Stapel entfernen: " + deletetos)
 
var stackOfInts = Stack<Int>()
print("Ganze Elemente in den Stapel einlegen: ")
stackOfInts.push(1)
stackOfInts.push(2)
print(stackOfInts.items);

Die Ausführungsresultate des Beispiels sind:

Einzelelemente in den String in den Stapel einlegen: 
["google", "w3codebox"]
Element aus dem Stapel entfernen: w3codebox
Ganze Elemente in den Stapel einlegen: 
[1, 2]

Stack ist im Wesentlichen gleich wie IntStack, der Platzhalter für den Typparameter Element ersetzt den tatsächlichen Int-Typ.

In den folgenden Beispielen wird Element in folgenden drei Stellen als Platzhalter verwendet:

  • erstellen items Attribute, verwenden Element eine leere Array-Instanz des Typs für den Initialisierung.

  • bestimmt push(_:) der einzigartige Parameter der Methode item der Typ muss sein Element Typen.

  • bestimmt pop() Der Rückgabetyp der Methode muss sein Element Typen.

Erweiterung generischer Typen

Wenn Sie einen generischen Typ erweitern (verwenden Sie den Schlüsselwort 'extension'), müssen Sie nicht in der Erweiterungsdefinition eine Typparameterliste bereitstellen. Es ist noch bequemer, dass die Typparameterliste, die in der ursprünglichen Typdefinition deklariert wurde, im Erweiterungsbereich verwendet werden kann, und die Parameternamen aus der ursprünglichen Typdefinition werden als Referenz für die Typparameter der ursprünglichen Definition verwendet.

Die folgende Beispiel-Erweiterung erweitert den generischen Typ Stack, indem sie eine lesbare berechnete Eigenschaft namens topItem hinzufügt, die das aktuelle Element des Stapelkopfes zurückgibt, ohne es aus dem Stapel zu entfernen:}}

Generisch

struct Stack<Element> {
    var items = [Element]()
    mutating func push(_ item: Element) {
        items.append(item)
    }
    mutating func pop() -> Element {
        return items.removeLast()
    }
}
 
extension Stack {
    var topItem: Element? {
       return items.isEmpty ? nil : items[items.count - 1]
    }
}
 
var stackOfStrings = Stack<String>()
print("Einzelelemente in den String in den Stapel einlegen:")
stackOfStrings.push("google")
stackOfStrings.push("w3codebox)
 
if let topItem = stackOfStrings.topItem {
    print("Der oberste Element im Stapel ist:\(topItem).")
}
 
print(stackOfStrings.items)

Das topItem-Attribut im Beispiel gibt eine optionale Wert vom Typ Element zurück. Wenn der Stapel leer ist, gibt topItem nil zurück; wenn der Stapel nicht leer ist, gibt topItem das letzte Element des Arrays items zurück.

Die Ausgabe des obigen Programms ist:

Einzelelemente in den String in den Stapel einlegen: 
Der oberste Element im Stapel ist: w3codebox.
["google", "w3codebox"]

Wir können auch eine vererbte Art durch Erweiterung eines bestehenden Typs spezifizieren.

Zum Beispiel bietet der Array-Typ von Swift bereits die Methode append(_:) an, ein count-Attribut und einen Index, der Int-Typindizes akzeptiert, um Elemente abzurufen. Diese Funktionen erfüllen die Anforderungen des Protokolls Container, daher müssen Sie einfach Array das Protokoll akzeptieren, um sie zu erweitern.

Nachfolgender Beispielcode erstellt eine leere Erweiterung:

extension Array: Container {}

Typbeschränkung

Typbeschränkungen spezifizieren einen Typparameter, der von einer bestimmten Klasse abgeleitet sein muss oder einem bestimmten Protokoll oder Protokollkette folgen muss.

Typbeschränkungsgrammatik

Sie können eine Typbeschränkung hinter einem Typargumentnamen durch einen Doppelpunkt trennen, um sie als Teil der Typargumentkette zu verwenden. Die Grundsyntax der Typbeschränkung für generische Funktionen ist wie folgt (und ähnlich der Syntax für generische Typen):

func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
    // Dies ist der Funktionskörper der generischen Funktion
}

Dieser Funktion gibt es zwei Typparameter. Der erste Typparameter T hat die Anforderung, dass T eine Unterklasse von SomeClass sein muss; der zweite Typparameter U hat die Anforderung, dass U dem SomeProtocol-Protokoll entsprechen muss.

Online-Beispiel

Generisch

// Nicht generische Funktion, sucht nach der Indexposition eines angegebenen Strings im Array
func findIndex(ofString valueToFind: String, in array: [String]) -> Int? {
    for (index, value) in array.enumerated() {
        if value == valueToFind {
            // Gefunden, geben Sie den Indexwert zurück
            return index
        }
    }
    return nil
}
 
 
let strings = ["google", "weibo", "taobao", "w3codebox", "facebook"]
if let foundIndex = findIndex(ofString: "w3codebox", in: strings) {
    print("w3Der Index von codebox beträgt (foundIndex)")
}

Der Index-Indikator beginnt bei 0.

Die Ausgabe des obigen Programms ist:

w3Der Index von codebox beträgt 3

Verknüpfte Klasse

In Swift wird der Schlüsselwort "associatedtype" verwendet, um Beispiele für verknüpfte Typen zu setzen.

Nachstehend ist ein Beispiel für die Definition eines Container-Protokolls gezeigt, das einen verknüpften Typ ItemType definiert.

Das Container-Protokoll spezifiziert nur drei Funktionen, die jeder Typ, der dem Container-Protokoll folgt, bereitstellen muss. Typen, die dem Protokoll folgen, können auch zusätzliche Funktionen bereitstellen, wenn sie diese drei Bedingungen erfüllen.

// Container-Protokoll
protocol Container
    associatedtype ItemType
    // Fügen Sie ein neues Element dem Container hinzu
    mutating func append(_ item: ItemType)
    // Zähle die Elemente im Container
    var count: Int { get }
    // Jedes Element im Container kann durch den Index Int abgerufen werden
    subscript(i: Int) -> ItemType { get }
}
// Der Stack-Strukturtyp folgt dem Container-Protokoll
struct Stack<Element>: Container {
    // Ursprüngliche Implementierung des Stack<Element>
    var items = [Element]()
    mutating func push(_ item: Element) {
        items.append(item)
    }
    mutating func pop() -> Element {
        return items.removeLast()
    }
    // Teil der Implementierung des Container-Protokolls
    mutating func append(_ item: Element) {
        self.push(item)
    }
    var count: Int {
        return items.count
    }
    subscript(i: Int) -> Element {
        return items[i]
    }
}
var tos = Stack<String>()
tos.push("google")
tos.push("w3codebox)
tos.push("taobao")
// Elementliste
print(tos.items)
// Anzahl der Elemente
print( tos.count)

Die Ausgabe des obigen Programms ist:

["google", "w3codebox, "taobao"]
3

WHERE-Ausdruck

Typenbeschränkungen stellen sicher, dass der Typ den Definitionseinschränkungen der Generikt Funktionen oder Klassen entspricht.

Sie können durch den WHERE-Ausdruck im Parameterliste Einschränkungen für die Parameter definieren.

Sie können einen WHERE-Ausdruck schreiben, der direkt hinter der Typparameterliste folgt, gefolgt von einem oder mehreren Einschränkungen für die verknüpften Typen sowie (oder) einer oder mehreren Gleichheitsbeziehungen zwischen Typen und verknüpften Typen.

Online-Beispiel

Nachstehendes Beispiel definiert eine generische Funktion allItemsMatch, um zu überprüfen, ob zwei Container-Beispiele die gleichen Elemente in der gleichen Reihenfolge enthalten.

Gibt true zurück, wenn alle Elemente übereinstimmen können, sonst false.

Generisch

// Container-Protokoll
protocol Container
    associatedtype ItemType
    // Fügen Sie ein neues Element dem Container hinzu
    mutating func append(_ item: ItemType)
    // Zähle die Elemente im Container
    var count: Int { get }
    // Jedes Element im Container kann durch den Index Int abgerufen werden
    subscript(i: Int) -> ItemType { get }
}
 
// // Generischer Typ TOS, der das Container-Protokoll befolgt
struct Stack<Element>: Container {
    // Ursprüngliche Implementierung des Stack<Element>
    var items = [Element]()
    mutating func push(_ item: Element) {
        items.append(item)
    }
    mutating func pop() -> Element {
        return items.removeLast()
    }
    // Teil der Implementierung des Container-Protokolls
    mutating func append(_ item: Element) {
        self.push(item)
    }
    var count: Int {
        return items.count
    }
    subscript(i: Int) -> Element {
        return items[i]
    }
}
// Erweiterung, um Array als Container zu verwenden
extension Array: Container {}
 
func allItemsMatch<C1: Container, C2: Container>
    (_ someContainer: C1, _ anotherContainer: C2) -> Bool
    wo C1.ItemType == C2.ItemType, C1.ItemType: Equatable {
        
        // Überprüfen Sie, ob beide Container die gleiche Anzahl von Elementen enthalten
        Wenn die Anzahl der Elemente in someContainer nicht der Anzahl der Elemente in anotherContainer entspricht {
            return false
        }
        
        // Überprüfen Sie, ob jedes Paar von Elementen gleich ist
        for i in 0..<someContainer.count {
            if someContainer[i] != anotherContainer[i] {
                return false
            }
        }
        
        // Alle Elemente stimmen überein, return true
        return true
}
var tos = Stack<String>()
tos.push("google")
tos.push("w3codebox)
tos.push("taobao")
 
var aos = ["google", "w3codebox, "taobao"]
 
if allItemsMatch(tos, aos) {
    print("Alle Elemente abgleichen")
} else {
    print("Elemente nicht übereinstimmen")
}

Die Ausgabe des obigen Programms ist:

Alle Elemente abgleichen