0Pricing
Swift Academy · Урок

Условное соответствие протоколу

Обеспечивайте соответствие обобщённых типов только при выполнении ограничений.

«Условное соответствие протоколу» — бесплатный урок 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 — локальная установка не требуется.

Все уроки этого курса

  1. Протоколы как контракты
  2. Реализации по умолчанию в расширениях
  3. Композиция протоколов
  4. Условное соответствие протоколу
← Назад к Swift Academy