Swift: Generics (Универсальные шаблоны)

Если бы библиотеки писали под конкретные классы, нас бы ждало дублирование кода, очень много дублирования кода, и много приведения типов.

И так для каждого типа.
Но лучше определить функцию которая будет работать с любым типом

— после имени функции, где T — заполнитель, указывающий на то как будет называться тип (в нашем случае переменные a и b — типа T), вместо T при вызове метода можно подставить любой существующий тип, Int, View, какой угодно что и обеспечивает необходимую гибкость
Если бы функция могла принимать два аргумента любого типа, можно было бы назначить функцию так

При вызове функции, она на основании типа переданных параметров поймет какие в этот раз будут типы T и U и на основании этого будет выполнять вычисления

Универсальными могут быть не только функции но и сами типы

Использовать T можно и как параметр функции и как возвращаемое значение и как тип для переменных

При расширении дженериков — мы не можем менять список заполнителей, мы используем те что были изначально определенны

По умолчанию заполнитель может быть любого типа, но часто бывает необходимо ввести ограничения на возможные типы, к примеру в качестве ключа в словаре может быть только тип реализующий протокол Hashable

Ограничения указываются через двоеточие, можно ограничить классом, можно протоколом (и их потомками соответственно)

Associated Types (Связанные типы)

Чтобы дать возможность протоколам не быть завязанными на конкретные типы вместо скобок с заполнителем ввели связанные типы.
Синтаксис:

К примеру определим протокол для контейнеров

В классе реализующему протокол со связанными типами необходимо указать конкретные тип для них
Синтаксис прост

Мы можем его реализовать так :

Или в дженерик варианте:

Мы даже не указываем определение для ItemType (typealias ItemType = T) — компилятор понимает это на автомате по типу T указанных в качестве параметров методов вместо ItemType

Если какой то тип уже удовлетворяет требованиям протокола но это нигде не закреплено формально — это можно сделать с помощью расширения с пустым телом

т.к. в Array уже и так определены методы перечисленные в протоколе

Связанные типы так же можно ограничить, в этот раз с помощью ключевого слова where и условий

К примеру представим себе функцию, которая должна будет возвратить true, если все значения контейнеров совпадут (те же значения в том же порядке) но не зависимо от конкретной реализации контейнера

where должно стоять после перечисления generic параметров. В нашем случае условия следующие
1) типы элементов внутри контейнеров должны совпадать (C1.ItemType == C2.ItemType)
2) тип элементов должен реализовывать протокол Equatable, чтобы элементы этого типа можно было сравнивать

Код для проверки демонстрации:


В случае Swift 2.0 — вызов функции будет отличаться
if allItemsMatch(stackOfStrings, anotherContainer: arrayOfStrings) {

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *