Что такое тип `any` в Swift?

Ответ

any — это экзистенциальный тип (existential type) в Swift, который представляет собой контейнер для значения любого конкретного типа, соответствующего протоколу. Он введен для явного указания на использование стирания типа (type erasure).

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

Пример:

protocol Drawable {
    func draw()
}

struct Circle: Drawable { func draw() { print("Рисую круг") } }
struct Square: Drawable { func draw() { print("Рисую квадрат") } }

// Коллекция экзистенциальных типов
let shapes: [any Drawable] = [Circle(), Square()]
for shape in shapes {
    shape.draw() // Динамический вызов метода
}
// Вывод:
// Рисую круг
// Рисую квадрат

Ключевые особенности и сравнение с some:

Критерий any Protocol some Protocol
Семантика "Любой тип, соответствующий протоколу" (экзистенциальный) "Конкретный, но неизвестный тип" (непрозрачный)
Гибкость Позволяет создавать гетерогенные коллекции ([any Drawable]). Требует, чтобы все значения в коллекции были одного конкретного типа.
Производительность Может требовать дополнительных затрат на упаковку (boxing) и динамическую диспетчеризацию. Позволяет компилятору проводить статическую оптимизацию.
Использование Когда нужна динамическая гибкость во время выполнения. Когда тип скрыт для абстракции, но фиксирован для компилятора (например, возвращаемый тип).

Важно: Используйте any осознанно, когда действительно требуется динамическое поведение. Для локальных абстракций часто предпочтительнее использовать дженерики (generics) или непрозрачные типы (some) из-за их лучшей производительности и безопасности типов.

Ответ 18+ 🔞

А, слушай, смотри, вот эта штука — any. Это ж, блядь, экзистенциальный тип, ну, existential type, если по-умному. По сути, это такой контейнер, куда можно запихнуть значение любого типа, который подходит под протокол. Его специально ввели, чтобы явно тыкать нам пальцем: «Вот тут, мудила, происходит стирание типа, запомни!».

Зачем это, на хуй, нужно? Ну чтобы можно было, например, собрать в одну кучу объекты разных типов, но которые все соответствуют одному протоколу. И при этом всем было ясно, что диспетчеризация тут будет динамическая, а не статическая.

Вот, смотри, пример, чтобы не быть мудаком:

protocol Drawable {
    func draw()
}

struct Circle: Drawable { func draw() { print("Рисую круг") } }
struct Square: Drawable { func draw() { print("Рисую квадрат") } }

// Коллекция экзистенциальных типов — вот тут магия!
let shapes: [any Drawable] = [Circle(), Square()]
for shape in shapes {
    shape.draw() // Вызовется динамически, ёпта!
}
// Вывод:
// Рисую круг
// Рисую квадрат

А теперь, чтобы не путать с some, вот тебе разжёванная таблица, блядь:

Критерий any Protocol some Protocol
Что означает «Любой тип, подходящий под протокол» (экзистенциальный) «Какой-то конкретный, но неизвестный тебе тип» (непрозрачный)
Гибкость Позволяет делать разношёрстные коллекции ([any Drawable]). Требует, чтобы вся коллекция была из одного конкретного типа, хоть ты и не знаешь какого.
Скорость Может тормозить из-за упаковки (boxing) и динамических вызовов. Компилятор может всё статически оптимизировать, потому что тип внутри фиксирован.
Когда юзать Когда тебе реально нужна динамика в рантайме. Когда тип скрыт для абстракции, но компилятору он известен (например, возвращаемое значение функции).

Главное, что нужно понять: не начинай везде пихать any просто так, от скуки. Если можно обойтись дженериками или some — используй их, ёпта! Они и быстрее, и безопаснее. any — это для особых случаев, когда без динамической хуйни реально не обойтись. Всё, вопрос закрыт.