0Pricing
Swift Academy · Урок

Композиция протоколов

Объединяйте требования нескольких протоколов с помощью &.

«Композиция протоколов» — бесплатный урок Swift Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Swift Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Swift Academy содержит 4 уроков всего.

Объединение протоколов

Иногда значение должно одновременно соответствовать нескольким протоколам. Swift позволяет составлять протоколы с помощью оператора &: SomeProtocol & AnotherProtocol.

protocol Named { var name: String { get } }
protocol Aged { var age: Int { get } }

Составной параметр

Параметр типа Named & Aged принимает любое значение, соответствующее обоим протоколам.

protocol Named { var name: String { get } }
protocol Aged { var age: Int { get } }

struct Person: Named, Aged {
    let name: String
    let age: Int
}

func intro(_ x: Named & Aged) {
    print(x.name + " is " + String(x.age))
}
intro(Person(name: "Sam", age: 28))

Почему не наследование

Механизм composition позволяет потребовать оба протокола в месте вызова без создания нового объединённого протокола. Это сохраняет протоколы небольшими и пригодными для повторного использования.

protocol Drawable { func draw() -> String }
protocol Resizable { func resize(_ f: Double) -> String }

struct Icon: Drawable, Resizable {
    func draw() -> String { "drawing" }
    func resize(_ f: Double) -> String { "x" + String(f) }
}

func render(_ v: Drawable & Resizable) {
    print(v.draw(), v.resize(2))
}
render(Icon())

Три протокола и более

Можно соединить столько протоколов, сколько необходимо, добавляя операторы &.

protocol A { func a() -> String }
protocol B { func b() -> String }
protocol C { func c() -> String }

struct X: A, B, C {
    func a() -> String { "a" }
    func b() -> String { "b" }
    func c() -> String { "c" }
}

func use(_ v: A & B & C) { print(v.a(), v.b(), v.c()) }
use(X())

Сочетание с классом

Можно объединить тип класса с протоколами: SomeClass & SomeProtocol требует, чтобы значение относилось к этому классу или его подклассу AND соответствовало протоколу.

class Vehicle { var speed = 0 }
protocol Electric { var battery: Int { get } }

class Tesla: Vehicle, Electric { var battery = 100 }

func check(_ v: Vehicle & Electric) {
    print(v.speed, v.battery)
}
check(Tesla())

Возврат составного типа

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

protocol Named { var name: String { get } }
protocol Aged { var age: Int { get } }
struct Person: Named, Aged { let name: String; let age: Int }

func makePerson() -> Named & Aged {
    Person(name: "Eve", age: 22)
}
let p = makePerson()
print(p.name, p.age)

typealias для composition

Дайте composition понятное имя с помощью typealias, чтобы повторно использовать его без повторения цепочки &.

protocol Codable2 { func encode() -> String }
protocol Loggable { func log() -> String }

typealias Persistable = Codable2 & Loggable

struct Record: Persistable {
    func encode() -> String { "data" }
    func log() -> String { "logged" }
}
func save(_ r: Persistable) { print(r.encode(), r.log()) }
save(Record())

Composition в коллекциях

Можно хранить значения составного типа в массивах, обращаясь к членам всех протоколов в каждом элементе.

protocol Named { var name: String { get } }
protocol Aged { var age: Int { get } }
struct P: Named, Aged { let name: String; let age: Int }

let group: [Named & Aged] = [P(name: "A", age: 1), P(name: "B", age: 2)]
for g in group { print(g.name, g.age) }

Composition со стандартными протоколами

Composition особенно полезен со встроенными протоколами. Например, можно потребовать одновременно CustomStringConvertible и Equatable.

func report<T>(_ items: [T]) where T: CustomStringConvertible & Equatable {
    for i in items { print(i.description) }
}
report([1, 2, 3])

Пустые протоколы как маркеры

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

protocol Secure {}
protocol Sendable2 { func send() -> String }

struct Packet: Secure, Sendable2 {
    func send() -> String { "sent securely" }
}
func transmit(_ p: Secure & Sendable2) { print(p.send()) }
transmit(Packet())

Композиция и обобщения

Композиция (A & B) скрывает конкретный тип, а обобщения (<T: A & B>) сохраняют его. Используйте обобщения, когда нужно связать типы параметров и возвращаемого значения.

protocol A { func a() -> String }
protocol B { func b() -> String }
struct S: A, B { func a() -> String { "a" }; func b() -> String { "b" } }

func generic<T: A & B>(_ x: T) -> T { print(x.a(), x.b()); return x }
_ = generic(S())

Проверка понимания

Проверьте, насколько хорошо Вы поняли композицию протоколов.

Итоги

Композиция протоколов с помощью & позволяет одновременно требовать соответствия нескольким протоколам (и, при необходимости, одному классу), не определяя новый объединённый протокол. Вы можете давать композициям имена с помощью typealias, использовать их в параметрах, возвращаемых значениях и коллекциях, а также отличать композицию от обобщений по сохранению конкретных типов.

Часто задаваемые вопросы

Урок «Композиция протоколов» бесплатный?

Да — полный текст урока «Композиция протоколов» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Swift Academy, подпишись на CoddyKit PRO. Курс Swift Academy содержит 4 уроков всего.

Чему я научусь в уроке «Композиция протоколов»?

Объединяйте требования нескольких протоколов с помощью &. Ты практикуешь Swift Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Swift Academy?

Предыдущий опыт не требуется. Swift Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Композиция протоколов»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Swift Academy?

Да. Каждый урок Swift Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

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

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