Композиция протоколов
Объединяйте требования нескольких протоколов с помощью &.
«Композиция протоколов» — бесплатный урок 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 — локальная установка не требуется.
Все уроки этого курса
- Протоколы как контракты
- Реализации по умолчанию в расширениях
- Композиция протоколов
- Условное соответствие протоколу