Экзистенциальные типы с any и стирание типа
Используйте any Protocol, учитывайте стоимость производительности и выбирайте обобщения, когда это предпочтительнее.
«Экзистенциальные типы с any и стирание типа» — бесплатный урок Swift Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Swift Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Swift Academy содержит 4 уроков всего.
Что такое экзистенциальный тип
Экзистенциальный тип помещает любое значение, соответствующее протоколу, в оболочку с единым интерфейсом; разрешение происходит во время выполнения.
protocol Drawable { func draw() }
struct Line: Drawable { func draw() { print("Line") } }
let d: any Drawable = Line()
d.draw()Ключевое слово any
Swift 5.7 требует указывать ключевое слово any перед именами протоколов, используемыми как экзистенциальные типы, чтобы явно обозначить упаковку.
func render(_ shape: any Drawable) {
shape.draw()
}
render(Line())Стоимость экзистенциальных типов
Экзистенциальные типы используют выделение памяти в куче и динамическую диспетчеризацию, поэтому могут работать медленнее обобщений со статической диспетчеризацией.
// Existential – dynamic dispatch, potential heap alloc
var shapes: [any Drawable] = [Line(), Line()]
// Generic – static dispatch, no boxing
func drawGeneric<T: Drawable>(_ s: T) { s.draw() }Проблема PAT и экзистенциальных типов
Протоколы со связанными типами (PAT) нельзя использовать как экзистенциальные типы без стирания типов.
protocol Container { associatedtype Item }
// var c: any Container // Swift 5.7 allows with "any" but loses Item infoПаттерн стирания типов
Обёртка со стёртым типом скрывает конкретный тип за структурой.
struct AnyDrawable: Drawable {
private let _draw: () -> Void
init<D: Drawable>(_ d: D) { _draw = d.draw }
func draw() { _draw() }
}AnySequence и AnyPublisher
Стандартная библиотека Swift и Combine поставляются с обёртками со стёртыми типами, такими как AnySequence и AnyPublisher.
import Combine
let subject = PassthroughSubject<Int, Never>()
let pub: AnyPublisher<Int, Never> = subject.eraseToAnyPublisher()eraseToAnyPublisher()
eraseToAnyPublisher() скрывает конкретную цепочку издателя, поэтому вызывающий код зависит только от AnyPublisher.
func fetch() -> AnyPublisher<String, Error> {
URLSession.shared.dataTaskPublisher(for: URL(string: "https://example.com")!)
.map { String(data: $0.data, encoding: .utf8) ?? "" }
.eraseToAnyPublisher()
}Когда уместны экзистенциальные типы
Используйте экзистенциальные типы для разнородных коллекций или когда точный тип неизвестен во время компиляции.
var widgets: [any Drawable] = [] // mixed concrete types OKПредпочитайте обобщённые типы экзистенциальным
По возможности заменяйте экзистенциальные типы обобщёнными, чтобы получить статическую диспетчеризацию и повысить производительность.
// Prefer this:
func draw<T: Drawable>(_ item: T) { item.draw() }
// Over this:
func draw(_ item: any Drawable) { item.draw() }Открытие экзистенциальных типов
Swift 5.7+ может автоматически открывать экзистенциальный тип при вызове обобщённой функции, извлекая лежащий в его основе тип.
func drawGeneric<T: Drawable>(_ d: T) { d.draw() }
let d: any Drawable = Line()
drawGeneric(d) // compiler opens the existential automaticallyСтирание типов и непрозрачные типы
Стирание типов скрывает тип для работы с разнородными значениями, а непрозрачные типы сохраняют идентичность одного согласованного возвращаемого типа.
let erased: any Drawable = Line() // runtime type unknown
let opaque: some Drawable = Line() // compile-time fixed typeБыстрая проверка
Какова основная причина снижения производительности при использовании экзистенциальных типов?
Итоги урока
Экзистенциальные типы (any Protocol) обеспечивают полиморфизм во время выполнения ценой динамической диспетчеризации. Стирание типов скрывает конкретные типы за стабильным интерфейсом. Для повышения производительности предпочитайте обобщённые типы, а экзистенциальные используйте для разнородных коллекций.
Часто задаваемые вопросы
Урок «Экзистенциальные типы с any и стирание типа» бесплатный?
Да — полный текст урока «Экзистенциальные типы с any и стирание типа» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Swift Academy, подпишись на CoddyKit PRO. Курс Swift Academy содержит 4 уроков всего.
Чему я научусь в уроке «Экзистенциальные типы с any и стирание типа»?
Используйте any Protocol, учитывайте стоимость производительности и выбирайте обобщения, когда это предпочтительнее. Ты практикуешь Swift Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Swift Academy?
Предыдущий опыт не требуется. Swift Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Экзистенциальные типы с any и стирание типа»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Swift Academy?
Да. Каждый урок Swift Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Ограничения обобщений и предложения where
- Непрозрачные типы с ключевым словом some
- Экзистенциальные типы с any и стирание типа
- Основные связанные типы и типизированные ошибки