Универсальное программирование — это стиль «компьютерного программирования, в котором алгоритмы записываются в терминах типов, которые будут указаны позже, которые затем создается при необходимости для определенных типов, предоставляемых в качестве параметров. — Википедия

Написание кода с помощью универсальных шаблонов — это способ написания функций и типов данных без указания того, какой именно тип необходимо использовать. Как следует из названия, общие типы не специфичны.

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

В этой части первой части я расскажу, как массивы, словари и необязательные элементы являются примерами дженериков. Часть вторая посвящена написанию универсальных классов и структур данных, написанию универсальных функций и ограничению универсальных типов. В третьей части обсуждаются типы Associates и общие положения Where.

Массивы как дженерики

Массив является примером универсального типа. Массив — это контейнер, который содержит любой тип вещей. В Swift у нас есть преимущество вывода типов, когда мы можем создать массив без явного объявления его типа. Поскольку мы НЕ ДОЛЖНЫ указывать тип любого массива (поскольку он выводится), массив как структура данных является универсальной.

let months = ["January", "February", "March"]

Выше у меня есть массив месяцев. Поскольку я задал параметры типа массива в виде строк, этому экземпляру months присваивается конкретный тип STRING. Другими словами, тип, который должен храниться в массиве, определяется при его объявлении.

Общий синтаксис для массивов

Хотя приведенный выше массив месяцев формально не объявляет тип как STRING, существует общий синтаксис для объявления массивов следующим образом:

var springMonths: Array<String> = []

Обратите внимание, что за словом Массив следует тип в угловых скобках ‹ ›. Мы можем указать имя нашего «универсального типа» между этими угловыми скобками. Для дженериков нормой является использование ‹T› в качестве заполнителя для любого универсального типа, на который мы ссылаемся.

Использование универсальных методов для массивов

Массивы, будучи универсальными, поставляются с универсальными методами, такими как .append().

springMonths.append("March")
springMonths.append("April")
springMonths.append("May")

Как вы заметили выше, я добавил месяцы «март», «апрель» и «июнь» к массиву springMonths.

Как вы думаете, что произойдет, если я напишу следующую строку кода:

springMonths.append(50)

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

Тогда ты прав! Поскольку мы объявили, что наш массив будет иметь тип STRING, все, что не является строкой, нарушит наш компилятор.

Словари как дженерики

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

Например, ниже я НЕ указываю СПЕЦИАЛЬНО тип словаря:

let monthDaysDictionary = ["January": 31, "February": 28, "March", 31, "April": 30, "May": 31, "June": 30, "July": 31, "August": 31, "September": 30, "October": 31, "November": 30, "December": 31]

Однако компилятор сделает вывод, что тип словаря будет STRING: INT. В результате у нас будет другая типобезопасная структура данных (это означает, что теперь в этот словарь можно добавлять только значения STRING: INT).

Факультативы как дженерики

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

let optionalMonth = Optional<String>.some("July")

Примечание. Если вам интересно, что это за .some, помните, что необязательные параметры имеют два состояния: SOME чего-то или NONE чего-то.

Чтобы развернуть дополнительный месяц выше, я бы сделал следующую необязательную привязку:

if let unwrappedOptionalMonth = optionalMonth { }

В приведенном выше развертывании необязательного мы берем универсальное значение типа T? и присвойте ему общее значение типа T (без вопросительного знака). Это означает, что if let можно использовать с любым универсальным типом.

Массивы, словари и опции — все это формы дженериков. У вас может быть массив любого типа данных, который вы хотите, даже объекты/модели, которые вы создаете самостоятельно. Вы также можете иметь словари любых типов (ключи и значения) (включая собственные объекты). Наконец, необязательные параметры являются общими в том смысле, что все они относятся к типу T? и может быть развернут, чтобы иметь тип T.

Ресурсы:

Документация Apple — дженерики