Découvrons le code générique en Swift :

Fonctions génériques


func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

Cette fonction permet d'interchanger la valeur de deux variables de type Int.

Pour interchanger la valeur de deux String ou Double, il faudrait écrire une nouvelle fonction quasi identique.

Les fonctions génériques peuvent fonctionner avec n'importe quel type. Voici une version générique de la fonction swapTwoInts(_:_:) ci-dessus, appelée swapTwoValues(_:_:) :


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

La version générique de la fonction utilise un espace réservé nom du type (appelé T, dans ce cas) au lieu d'un véritable nom de type ( par exemple Int, String ou Double). Le nom du type d'espace réservé ne dit rien sur ce que T doit être, mais il indique que les deux a et b doivent être du même type T.

La fonction swapTwoValues(_:_:) peut maintenant être appelée de la même manière que swapTwoInts, sauf qu'elle peut recevoir deux valeurs de n'importe quel type, à condition que ces deux valeurs soient du même type l'une que l'autre.

Types génériques


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

Elément définit un nom d'espace réservé pour un type à fournir ultérieurement. Ce type Element peut être appelé n'importe où dans la définition de la structure.

Extension d'un type générique

L'exemple suivant étend le type générique de Stack pour ajouter une propriété calculée en lecture seule appelée topItem, qui renvoie l'élément supérieur de la pile sans le sortir de la pile :


extension Stack {
    var topItem: Element? {
        return items.isEmpty ? nil : items[items.count - 1]
    }
}

Syntaxe de contraintes de types

Vous écrivez des contraintes de types en plaçant une seule contrainte de classe ou de protocole après le nom d'un paramètre de type, séparé par deux points, dans le cadre de la liste des paramètres de types. La syntaxe de base des contraintes de types sur une fonction générique est indiquée ci-dessous (bien que la syntaxe soit la même pour les types génériques) :


func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
    // function body goes here
}