Latest web development tutorials

Swift Generics

Swift offre une flexibilité générique et vous permet d'écrire des fonctions réutilisables et types.

bibliothèque standard Swift est construit par code générique.

tableaux Swift et les types de dictionnaires sont ensemble générique.

Vous pouvez créer un tableau Int, vous pouvez créer un tableau de chaînes, ou même ensemble de données peut être tout autre type de Swift.

L'exemple suivant est un échange de fonction non générique pour l'échange de 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)")

La sortie de l'exécution du programme ci-dessus est la suivante:

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

Fonctions génériques peuvent accéder à tout type, comme Int ou String.

L'exemple suivant est une fonction générique pour l'échange de swap 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)")

La sortie de l'exécution du programme ci-dessus est la suivante:

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

Version générique de cette fonction en utilisant le nom du type d'espace réservé (généralement représenté par la lettre T dans ce cas) au lieu des noms de type réels (tels que Int, String ou Double). Placeholder nom de type ne doit pas suggérer ce type T, mais il suggère un et b doit être du même type T, quel que soit le type T représente. Seul l'échange (_: _ :) fonction lorsqu'ils sont transmis dans chaque type d'appel afin de déterminer le type réel T représente.

Une autre différence est que ce dernier nom de la fonction suivi du nom générique du type d'espace réservé (T) est placé entre crochets angulaires ( ). Les équerres ont dit Swift que T est l'autocommutateur (_: _ :) en fonction du type défini. Comme T est un type d'espace réservé nommé, Swift est de ne pas trouver le nom du type T. réelle


Type générique

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

classes personnalisées, structures et énumérations appliquées à tout type de matrice et de l'utilisation dictionnaire.

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()

La sortie de l'exécution du programme ci-dessus est la suivante:

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

type générique Extended

Comme vous étendez le temps d'un type générique (en utilisant la clé d'extension), vous ne devez fournir une liste de paramètres de type dans la définition élargie. Plus pratique est les paramètres de type définis dans la déclaration de type d'origine dans la liste peut être étendue à l'utilisation et les noms des paramètres du type original de référence seront utilisés pour définir le paramètre de type d'origine.

Exemples

L'exemple suivant étend le type de TOS générique, pour ajouter une propriété en lecture seule nommé premier calcul, il sera de retour au sommet actuel des éléments de pile et ne sera pas retiré de la pile.

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)")
}

La sortie de l'exécution du programme ci-dessus est la suivante:

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

Type de contrainte

Type de contrainte spécifie qu'un paramètre de type doit hériter de la classe spécifiée ou suivre un protocole ou d'une composition spécifique.

syntaxe de contrainte de type

Vous pouvez écrire une contrainte de type à l'arrière d'un des noms de paramètres de type, divisé par deux points, dans le cadre de la chaîne type de paramètre. De tels actes sur la base du type de syntaxe contrainte pour les fonctions génériques sont les suivantes (le même type générique de la syntaxe):

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

Exemples

// 函数可以作用于查找一字符串数组中的某个字符串
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)")
}

La sortie de l'exécution du programme ci-dessus est la suivante:

llama 的下标索引值为 2

Des exemples du type d'association

typealias Swift utilisent des mots clés pour définir le type d'association.

Définir un protocole, parfois déclarer un ou type de protocole partie de la définition plus associée est très utile car.

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)

La sortie de l'exécution du programme ci-dessus est la suivante:

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

Lorsque les déclarations

Le type de contrainte pour assurer la conformité avec la définition du type de fonction ou de classe générique contrainte.

Vous pouvez définir les paramètres de l'instruction où la contrainte dans la liste des paramètres.

Où vous pouvez écrire une déclaration, suivie de la liste des paramètres de type à l'arrière, lorsque la déclaration est suivie par un ou plusieurs types de contraintes pour l'association, et (ou) l'équivalent d'un ou plusieurs types et types d'association entre (égalité) relation.

Exemples

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

Si tous les éléments peuvent correspondre, puis revenir à une valeur booléenne true, sinon il est faux.

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)

La sortie de l'exécution du programme ci-dessus est la suivante:

["Swift"]
["Swift", "泛型"]
["Swift", "泛型", "Where 语句"]
["Swift", "泛型", "Where 语句"]