Найдите причину ошибки компиляции: какого контекста не хватает литералу nil?
let values = [nil]
print(values)
Код не компилируется, потому что nil не имеет самостоятельного типа: это литерал, который должен быть преобразован в конкретный Optional<Wrapped>. В массиве [nil] Swift не может вывести тип Wrapped, поэтому нужно явно задать тип элемента, например [Int?].
Optionals в Swift предназначены для явного представления наличия или отсутствия значения в статически типизированной системе. Такой подход заменяет неявные null-значения контекстом конкретного типа Optional<Wrapped> и позволяет компилятору контролировать операции с потенциально отсутствующим значением.
Из-за этого nil не является универсальным значением вроде отдельного базового типа. Он может обозначать .none только после того, как известен тип обёртки.
В выражении [nil] компилятор видит массив, но не знает, каким должен быть его элемент: Int?, String?, User? или другим Optional. Выбор произвольного типа нарушил бы предсказуемость вывода типов и мог бы изменить дальнейшее поведение программы.
Ошибка возникает на этапе компиляции, до выполнения кода. Это безопаснее, чем выбирать тип динамически, но требует явно предоставить контекст там, где одних литералов недостаточно.
nil можно рассматривать как литерал, который создаёт значение .none некоторого Optional-типа. Например, запись [Int?] сообщает компилятору, что каждый элемент массива имеет тип Optional<Int>:
Здесь первый и третий элементы имеют состояние .none, а второй содержит Int со значением 7. Сам массив имеет тип [Int?], а не [Int], поскольку отсутствие значения является допустимым состоянием каждого элемента.
Контекст можно задать не только аннотацией переменной, но и параметром функции или явным типом элемента. Например, вызов accept([nil]) с функцией accept(_ values: [Int?]) компилируется, потому что сигнатура функции предоставляет необходимый контекст.
Компромисс состоит в том, что явная аннотация делает код немного длиннее, зато фиксирует доменный тип и предотвращает случайный выбор неподходящего Wrapped.
Допустим, API собирает результаты загрузки идентификаторов пользователей, где nil означает, что конкретный идентификатор отсутствует. Вариант let values = [nil] не задаёт модели данных и не компилируется.
Можно использовать [Any?], но это ослабит статическую типизацию: массив сможет содержать значения разных типов. Лучше выбрать [Int?], если идентификаторы целочисленные: компилятор проверит все последующие операции, а смысл отсутствующего идентификатора останется однозначным.
Почему [nil, 42] обычно выводится как [Int?]?
Числовой литерал 42 предоставляет типовой контекст для Wrapped, а nil может быть преобразован в Optional<Int>. Поэтому массив получает тип [Int?]. Важен не сам nil, а наличие другого элемента, из которого можно вывести обёрнутый тип.
Почему пустой массив нельзя объявить как let values = [] без контекста?
Пустой литерал массива не содержит элементов, поэтому не сообщает компилятору тип элемента. Объявление let values: [Int?] = [] корректно, потому что аннотация задаёт этот тип явно. Аналогично работает передача [] в функцию, параметр которой имеет конкретный тип массива.
Почему вызов func make<T>() -> T? { nil } сам по себе не определяет T?
Возвращаемое значение .none не содержит экземпляра T, из которого можно было бы вывести параметр типа. Вызов становится однозначным только при наличии внешнего контекста, например let value: Int? = make(). Это тот же принцип: nil сообщает состояние Optional, но не определяет его Wrapped.