Génériques Swift


Swift fournit des génériques qui vous permettent d'écrire des fonctions et des types flexibles et réutilisables.

La bibliothèque standard Swift est construite avec du code générique.

Les types de tableaux et de dictionnaires de Swift sont tous deux des ensembles génériques.

Vous pouvez créer un tableau Int, un tableau String ou même tout autre tableau de données de type Swift.

L'exemple suivant est un échange de fonction non générique utilisé pour échanger deux valeurs Int :

// 定义一个交换两个变量的函数
func exchange(inout a: Int, inout b: Int) {
    let temp = a
    a = b
    b = temp
}

var numb1 = 100
var numb2 = 200

print("交换前数据: \(numb1) 和 \(numb2)")
exchange(&numb1, b: &numb2)
print("交换后数据: \(numb1) 和 \(numb2)")

Le résultat de sortie de l'exécution du programme ci-dessus est :

交换前数据: 100 和 200
交换后数据: 200 和 100

Générique les fonctions peuvent accéder à n’importe quel type, tel que Int ou String.

L'exemple suivant est un échange de fonctions générique utilisé pour échanger deux valeurs Int et String :

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

var numb1 = 100
var numb2 = 200

print("交换前数据:  \(numb1) 和 \(numb2)")
exchange(&numb1, b: &numb2)
print("交换后数据: \(numb1) 和 \(numb2)")

var str1 = "A"
var str2 = "B"

print("交换前数据:  \(str1) 和 \(str2)")
exchange(&str1, b: &str2)
print("交换后数据: \(str1) 和 \(str2)")

Le résultat de sortie de l'exécution du programme ci-dessus est :

交换前数据:  100 和 200
交换后数据: 200 和 100
交换前数据:  A 和 B
交换后数据: B 和 A

Le type générique de cette fonction La version utilise un nom de type d'espace réservé (généralement représenté par la lettre T dans ce cas) au lieu du nom de type réel (tel que Int, String ou Double). Le nom du type d'espace réservé n'indique pas quel type T doit être, mais il laisse entendre que a et b doivent être du même type T, quel que soit le type T représenté. Seul le type réel transmis à chaque fois que la fonction Exchange(_:_:) est appelée peut déterminer le type que T représente.

Une autre différence est que le nom du type d'espace réservé (T) qui suit le nom de la fonction générique est placé entre crochets (


Type générique

Swift vous permet de définir vos propres types génériques.

Les classes, structures et énumérations personnalisées fonctionnent avec n'importe quel type, tout comme Array et Dictionary

struct TOS<T> {
    var items = [T]()
    mutating func push(item: T) {
        items.append(item)
    }
    
    mutating func pop() -> T {
        return items.removeLast()
    }
}

var tos = TOS<String>()
tos.push("Swift")
print(tos.items)

tos.push("泛型")
print(tos.items)

tos.push("类型参数")
print(tos.items)

tos.push("类型参数名")
print(tos.items)


let deletetos = tos.pop()

Le programme ci-dessus est :

["Swift"]
["Swift", "泛型"]
["Swift", "泛型", "类型参数"]
["Swift", "泛型", "类型参数", "类型参数名"]
<🎜. >
Type générique étendu

Lorsque vous étendez un type générique (à l'aide du mot-clé extension), vous n'avez pas besoin de l'inclure dans la définition de l'extension. Fournissez une liste de paramètres de type Encore plus pratique, le paramètre type. La liste déclarée dans la définition de type d'origine est disponible dans l'extension, et les noms de paramètres du type d'origine sont utilisés comme références aux paramètres de type dans la définition d'origine >

Exemple

L'exemple suivant étend le type TOS générique. et ajoute une propriété calculée en lecture seule nommée first, qui renverra l'élément en haut de la pile actuelle sans le déplacer de la pile Sauf. L'exécution du programme ci-dessus est :

struct TOS<T> {
    var items = [T]()
    mutating func push(item: T) {
        items.append(item)
    }
    
    mutating func pop() -> T {
        return items.removeLast()
    }
}

var tos = TOS<String>()
tos.push("Swift")
print(tos.items)

tos.push("泛型")
    print(tos.items)
    
    tos.push("类型参数")
    print(tos.items)
    
    tos.push("类型参数名")
    print(tos.items)

// 扩展泛型 TOS 类型
extension TOS {
    var first: T? {
        return items.isEmpty ? nil : items[items.count - 1]
    }
}

if let first = tos.first {
    print("栈顶部项:\(first)")
}

Contrainte de type

La contrainte de type spécifie une classe qui doit être héritée de la classe spécifiée

Syntaxe de contrainte de type
.

Vous pouvez écrire une contrainte de type après un nom de paramètre de type, séparé par deux points, en tant que type faisant partie de la chaîne de paramètres. La syntaxe de base de cette contrainte de type sur une fonction générique est la suivante (identique à la syntaxe de. types génériques) :

["Swift"]
["Swift", "泛型"]
["Swift", "泛型", "类型参数"]
["Swift", "泛型", "类型参数", "类型参数名"]
栈顶部项:类型参数名

Exemple

func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
    // 这里是函数主体
}

La sortie d'exécution du programme ci-dessus Le résultat est :

// 函数可以作用于查找一字符串数组中的某个字符串
func findStringIndex(array: [String], _ valueToFind: String) -> Int? {
    for (index, value) in array.enumerate() {
        if value == valueToFind {
            return index
        }
    }
    return nil
}

let strings = ["cat", "dog", "llama", "parakeet", "terrapin"]
if let foundIndex = findStringIndex(strings, "llama") {
    print("llama 的下标索引值为 \(foundIndex)")
}

Instance de type associée

Le mot-clé typealias est utilisé dans Swift pour définir le type associé.

Lors de la définition d'un protocole, parfois un ou est déclaré. Il est très utile d'avoir plusieurs types associés dans le cadre de la définition du protocole
llama 的下标索引值为 2

. Le résultat de l'exécution du programme ci-dessus est :

protocol Container {
    // 定义了一个ItemType关联类型
    typealias ItemType
    mutating func append(item: ItemType)
    var count: Int { get }
    subscript(i: Int) -> ItemType { get }
}

// 遵循Container协议的泛型TOS类型
struct TOS<T>: Container {
    // original Stack<T> implementation
    var items = [T]()
    mutating func push(item: T) {
        items.append(item)
    }
    
    mutating func pop() -> T {
        return items.removeLast()
    }
    
    // conformance to the Container protocol
    mutating func append(item: T) {
        self.push(item)
    }
    
    var count: Int {
        return items.count
    }
    
    subscript(i: Int) -> T {
        return items[i]
    }
}

var tos = TOS<String>()
tos.push("Swift")
print(tos.items)

tos.push("泛型")
print(tos.items)

tos.push("参数类型")
print(tos.items)

tos.push("类型参数名")
print(tos.items)

L'instruction Where

les contraintes de type peuvent garantir que le type est conforme aux contraintes de définition d'une fonction ou d'une classe générique

.

Vous pouvez définir des contraintes de paramètres via les instructions Where dans la liste des paramètres.

Vous pouvez écrire une instruction Where immédiatement après la liste des paramètres de type, suivie d'une ou plusieurs contraintes sur le type associé, et/ou d'une ou plusieurs contraintes entre le type et la relation d'égalité associée.

Exemple

L'exemple suivant définit une fonction générique nommée allItemsMatch pour vérifier si deux instances de Container contiennent les mêmes éléments dans le même ordre.

Si tous les éléments peuvent correspondre, renvoyez une valeur booléenne vraie, sinon elle sera fausse.

["Swift"]
["Swift", "泛型"]
["Swift", "泛型", "参数类型"]
["Swift", "泛型", "参数类型", "类型参数名"]

Le résultat de sortie de l'exécution du programme ci-dessus est :

protocol Container {
    typealias ItemType
    mutating func append(item: ItemType)
    var count: Int { get }
    subscript(i: Int) -> ItemType { get }
}

struct Stack<T>: Container {
    // original Stack<T> implementation
    var items = [T]()
    mutating func push(item: T) {
        items.append(item)
    }
    
    mutating func pop() -> T {
        return items.removeLast()
    }
    
    // conformance to the Container protocol
    mutating func append(item: T) {
        self.push(item)
    }
    
    var count: Int {
        return items.count
    }
    
    subscript(i: Int) -> T {
        return items[i]
    }
}

func allItemsMatch<
    C1: Container, C2: Container
    where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
    (someContainer: C1, anotherContainer: C2) -> Bool {
        // 检查两个Container的元素个数是否相同
        if someContainer.count != anotherContainer.count {
            return false
        }
        
        // 检查两个Container相应位置的元素彼此是否相等
        for i in 0..<someContainer.count {
            if someContainer[i] != anotherContainer[i] {
                return false
            }
        }
        // 匹配所有项,返回 true
        return true
}

var tos = Stack<String>()
tos.push("Swift")
print(tos.items)

tos.push("泛型")
print(tos.items)

tos.push("Where 语句")
print(tos.items)

var eos = ["Swift", "泛型", "Where 语句"]
print(eos)