0Pricing
Swift Academy · Урок

Реализации по умолчанию в расширениях

Предоставляйте общее поведение через расширения протоколов.

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

Проблема

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

protocol Greeter {
    func greet() -> String
}

Добавление реализации по умолчанию

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

protocol Greeter { func greet() -> String }

extension Greeter {
    func greet() -> String { "Hello!" }
}

struct Robot: Greeter {}
print(Robot().greet())

Переопределение реализации по умолчанию

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

protocol Greeter { func greet() -> String }
extension Greeter { func greet() -> String { "Hello!" } }

struct French: Greeter {
    func greet() -> String { "Bonjour!" }
}
print(French().greet())

Добавление дополнительных методов

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

protocol Named { var name: String { get } }

extension Named {
    func loudName() -> String { name.uppercased() }
}

struct City: Named { let name: String }
print(City(name: "paris").loudName())

Вычисляемые свойства по умолчанию

Расширения также могут предоставлять вычисляемые свойства по умолчанию.

protocol Sized {
    var width: Double { get }
    var height: Double { get }
}

extension Sized {
    var area: Double { width * height }
}

struct Rect: Sized { let width: Double; let height: Double }
print(Rect(width: 2, height: 5).area)

Построение на основе требований

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

protocol Summable {
    var values: [Int] { get }
}

extension Summable {
    var total: Int { values.reduce(0, +) }
}

struct Cart: Summable { let values: [Int] }
print(Cart(values: [10, 20, 30]).total)

Расширения с ограничениями

Используйте предложение where, чтобы реализация по умолчанию применялась только при выполнении дополнительных условий. Здесь реализация существует только тогда, когда Self также соответствует Equatable.

protocol Container {
    associatedtype Item
    var items: [Item] { get }
}

extension Container where Item: Equatable {
    func contains(_ x: Item) -> Bool { items.contains(x) }
}

struct Bag: Container { let items: [Int] }
print(Bag(items: [1, 2, 3]).contains(2))

Реализация и требование по умолчанию

Можно объявить метод в протоколе AND предоставить реализацию по умолчанию. Его перечисление в протоколе включает динамическую диспетчеризацию через тип протокола.

protocol Logger {
    func log() -> String
}
extension Logger {
    func log() -> String { "default log" }
}

struct A: Logger {}
struct B: Logger { func log() -> String { "B log" } }

let loggers: [Logger] = [A(), B()]
for l in loggers { print(l.log()) }

Особенность статической диспетчеризации

Если метод находится ONLY в расширении, но не в протоколе, вызовы через значение типа протокола используют версию из расширения, даже если конкретный тип определил собственную. Объявите метод в протоколе для динамической диспетчеризации.

protocol P {}
extension P { func who() -> String { "P-default" } }
struct Q: P { func who() -> String { "Q" } }

let direct = Q()
let asP: P = Q()
print(direct.who())
print(asP.who())

Уменьшение шаблонного кода

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

protocol Identifiable { var id: Int { get } }
extension Identifiable {
    var tag: String { "ID-" + String(id) }
}
struct Order: Identifiable { let id: Int }
print(Order(id: 7).tag)

Объединение нескольких расширений

Для удобства организации можно разделить реализации по умолчанию между несколькими расширениями; все они дополняют соответствующий тип.

protocol Money { var cents: Int { get } }
extension Money { var dollars: Double { Double(cents) / 100 } }
extension Money { var label: String { "$" + String(format: "%.2f", dollars) } }

struct Price: Money { let cents: Int }
print(Price(cents: 1299).label)

Быстрая проверка

Проверьте своё понимание реализаций по умолчанию в расширениях протоколов.

Итоги

Расширения протоколов предоставляют реализации по умолчанию, позволяя соответствующим типам наследовать общее поведение и при необходимости переопределять его. Можно добавлять дополнительные методы и вычисляемые свойства, ограничивать реализации по умолчанию с помощью where, а также использовать правило статической и динамической диспетчеризации: для динамической диспетчеризации объявляйте метод в протоколе.

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

Урок «Реализации по умолчанию в расширениях» бесплатный?

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

Чему я научусь в уроке «Реализации по умолчанию в расширениях»?

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

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

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

Сколько времени занимает урок «Реализации по умолчанию в расширениях»?

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

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

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

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

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