Условное соответствие протоколу
Обеспечивайте соответствие обобщённых типов только при выполнении ограничений.
«Условное соответствие протоколу» — бесплатный урок Swift Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Swift Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Swift Academy содержит 4 уроков всего.
Что такое условное соответствие
Условное соответствие позволяет обобщённому типу соответствовать протоколу только тогда, когда его параметры типов удовлетворяют определённым ограничениям. Классический пример: Array соответствует Equatable только в том случае, если его Element соответствует Equatable.
extension Array where Element: Equatable {
func allEqual(to x: Element) -> Bool {
allSatisfy { $0 == x }
}
}Встроенный пример
Стандартная библиотека уже использует этот механизм: [Int] соответствует Equatable, потому что ему соответствует Int. Два массива сравниваются поэлементно.
let a = [1, 2, 3]
let b = [1, 2, 3]
print(a == b)Объявление условного соответствия
Напишите расширение, добавляющее соответствие протоколу с помощью условия where. Здесь оболочка соответствует Equatable только тогда, когда этому протоколу соответствует её тип значения.
struct Pair<T> {
let first: T
let second: T
}
extension Pair: Equatable where T: Equatable {
static func == (l: Pair, r: Pair) -> Bool {
l.first == r.first && l.second == r.second
}
}
print(Pair(first: 1, second: 2) == Pair(first: 1, second: 2))Почему ограничение важно
Без этого ограничения компилятор не смог бы синтезировать ==, поскольку для сравнения обёрнутого значения само значение должно поддерживать сравнение. Условие where предоставляет именно такую гарантию.
struct Box<T> { let value: T }
extension Box: Equatable where T: Equatable {}
print(Box(value: "hi") == Box(value: "hi"))
print(Box(value: 5) == Box(value: 9))Условное соответствие Codable
Можно условно соответствовать Codable. Контейнер доступен для кодирования только тогда, когда его элемент также доступен для кодирования.
struct Wrapper<T> { let payload: T }
extension Wrapper: Codable where T: Codable {}
let w = Wrapper(payload: 42)
let data = try! JSONEncoder().encode(w)
print(String(data: data, encoding: .utf8)!)Несколько ограничений
Условие where может содержать несколько требований, разделённых запятыми.
struct Stack<T> { var items: [T] = [] }
extension Stack where T: Comparable {
func maxItem() -> T? { items.max() }
}
var s = Stack<Int>()
s.items = [3, 9, 1]
print(s.maxItem()!)Условное соответствие CustomStringConvertible
Сделайте тип пригодным для вывода только тогда, когда его содержимое пригодно для вывода, составляя описания из элементов.
struct Labeled<T> { let label: String; let value: T }
extension Labeled: CustomStringConvertible where T: CustomStringConvertible {
var description: String { label + ": " + value.description }
}
print(Labeled(label: "Age", value: 30))Вложенное условное соответствие
Условное соответствие образует композицию: массив массивов Int соответствует Equatable, потому что каждый уровень передаёт это ограничение дальше.
let grid1 = [[1, 2], [3, 4]]
let grid2 = [[1, 2], [3, 4]]
print(grid1 == grid2)Ограничение другим протоколом
Условие where может требовать, чтобы элемент соответствовал определённому Вами протоколу, открывая доступ к поведению, построенному на этом протоколе.
protocol Priced { var price: Double { get } }
struct Item: Priced { let price: Double }
extension Array where Element: Priced {
var totalPrice: Double { reduce(0) { $0 + $1.price } }
}
print([Item(price: 1.5), Item(price: 2.5)].totalPrice)Ограничения равенства типов
Можно ограничить связанный тип конкретным типом с помощью ==. Здесь методы применяются только к массивам String.
extension Array where Element == String {
func joinedUpper() -> String {
map { $0.uppercased() }.joined(separator: "-")
}
}
print(["a", "b", "c"].joinedUpper())Как это использует компилятор
Условное соответствие позволяет компилятору предоставлять возможности протокола только тогда, когда они действительно допустимы, поэтому generic-код остаётся безопасным и максимально пригодным для повторного использования.
struct Optional2<T> { let value: T? }
extension Optional2: Equatable where T: Equatable {
static func == (l: Optional2, r: Optional2) -> Bool { l.value == r.value }
}
print(Optional2(value: 1) == Optional2(value: 1))Проверка понимания
Проверьте, насколько хорошо Вы поняли условное соответствие.
Итоги
Условное соответствие использует конструкцию extension Type: Protocol where ..., чтобы устанавливать соответствие только тогда, когда параметры типов удовлетворяют ограничениям. Вы рассмотрели Equatable, Codable и CustomStringConvertible, ограничения протоколами, ограничения равенства типов (==) и вложенные конструкции. Это помогает сохранять обобщённые типы безопасными и пригодными для повторного использования.
Часто задаваемые вопросы
Урок «Условное соответствие протоколу» бесплатный?
Да — полный текст урока «Условное соответствие протоколу» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Swift Academy, подпишись на CoddyKit PRO. Курс Swift Academy содержит 4 уроков всего.
Чему я научусь в уроке «Условное соответствие протоколу»?
Обеспечивайте соответствие обобщённых типов только при выполнении ограничений. Ты практикуешь Swift Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Swift Academy?
Предыдущий опыт не требуется. Swift Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Условное соответствие протоколу»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Swift Academy?
Да. Каждый урок Swift Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Протоколы как контракты
- Реализации по умолчанию в расширениях
- Композиция протоколов
- Условное соответствие протоколу