В чем разница между ключевыми словами some и any для протоколов в Swift?

«В чем разница между ключевыми словами some и any для протоколов в Swift?» — вопрос из категории Swift Core, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

some (непрозрачный тип) и any (экзистенциальный тип) — это два способа абстрагирования типов через протоколы, но с фундаментальными различиями в производительности и семантике.

some (Opaque Type)

  • Указывает, что возвращается конкретный, фиксированный тип, реализующий протокол. Конкретный тип известен компилятору, но скрыт от вызывающей стороны.
  • Статическая диспетчеризация: вызовы методов разрешаются на этапе компиляции, что дает максимальную производительность.
  • Требует, чтобы из одной точки возврата всегда возвращался один и тот же конкретный тип.
func makeVehicle() -> some Vehicle {
    return Car() // Компилятор знает, что это Car, но для внешнего кода это "some Vehicle"
}
// let v = makeVehicle() // Тип v — some Vehicle (фактически Car)

any (Existential Type)

  • Указывает на любой тип, реализующий протокол. Конкретный тип может меняться и определяется в runtime.
  • Динамическая диспетчеризация: вызовы методов проходят через таблицу виртуальных функций (witness table), что добавляет небольшие накладные расходы.
  • Позволяет хранить в одной коллекции объекты разных типов, реализующих один протокол.
func wash(_ vehicle: any Vehicle) {
    // Принимает любой тип, реализующий Vehicle
    vehicle.clean()
}

var garage: [any Vehicle] = [Car(), Bicycle()] // Массив разных типов
Ключевые отличия: Аспект some any
Производительность Выше (статическая диспетчеризация) Ниже (динамическая диспетчеризация, boxинг)
Гибкость Один конкретный тип Любой совместимый тип
Использование Возвращаемые типы, свойства Параметры, коллекции гетерогенных типов

Совет: По умолчанию предпочитайте some для возвращаемых типов из-за производительности. Используйте any, когда нужна runtime-гибкость.