История вопроса:
Opaque types (some) появились с Swift 5.1 и открыли новый способ абстракции возвращаемого значения функции или свойства, когда тип известен компилятору, но скрыт от пользователя. Это альтернатива protocol existentials (any Protocol), но с жёсткой привязкой к конкретному типу внутри функции.
Проблема: Когда функция возвращает протокол с associatedtype (например, Sequence), нельзя напрямую написать:
func makeNumberSequence() -> Sequence { ... } // ошибка
Protocol existentials позволяют возвращать любую реализацию, но не гарантируют один и тот же тип при каждом вызове:
func foo() -> any View { ... }
Это приводит к непредсказуемости и слабому type safety.
Решение: Использовать opaque result type:
func makeNumbers() -> some Sequence { [1, 2, 3] }
Теперь компилятор точно знает фактический возвращаемый тип, но он скрыт снаружи. Это даёт оптимизации производительности, safety, позволяет использовать SwiftUI DSL, облегчает обмен типами между модулями.
Ключевые особенности:
Могут ли opaque types использоваться для хранения значения (как свойства класса)?
Нет. Opaque types применяются только для возвращаемых значений функции или computed properties. Для хранения значения или массива значений используют existentials (any Protocol).
Могут ли разные ветви одной функции возвращать разные типы с some?
Нет. Компилятор требует, чтобы обе (или все) ветви возвращали один и тот же конкретный тип, иначе будет ошибка:
func foo(flag: Bool) -> some Sequence { if flag { return [1, 2, 3] } else { return ["a", "b", "c"] // ошибка } }
Можно ли использовать some для идентификации возвращаемого типа между несколькими функциями?
Нет. Каждая функция с some возвращает свой уникальный скрытый тип, даже если фактически это один и тот же массив. Использовать результат одной функции как параметр в другую нельзя, если обе используют some с разными протоколами или разными скрытыми типами.
В проекте всё возвращается через any Protocol, коллекции теряют типизацию, появляются баги при downcast-e, тормозит compile-time оптимизация.
Плюсы:
Минусы:
В SwiftUI-дизайне компоненты возвращают some View, каждый модуль чётко определяет внутренний тип. Размер бандла сокращается, сборка ускоряется.
Плюсы:
Минусы: