Представьте вызов функции, принимающей замыкание: откуда Swift берёт типы его неаннотированных параметров?
Swift обычно выводит типы неаннотированных параметров замыкания из контекстного типа, который задаётся ожидаемым типом параметра функции. Поэтому при передаче замыкания в функцию компилятор анализирует её сигнатуру, подставляет типы параметров и проверяет тело замыкания статически.
Если контекст отсутствует или остаётся неоднозначным, типы нужно указать явно либо изменить окружающий код так, чтобы ожидаемый тип стал однозначным.
Вывод типов в замыканиях уменьшает повторение информации: типы уже описаны в сигнатуре функции, поэтому дублировать их при каждом вызове необязательно. Это сохраняет статическую типизацию, но делает короткие операции более компактными.
Подход особенно полезен для функций высшего порядка, где замыкание передаётся как действие: преобразование, фильтрация, сортировка или обработка события.
Без понимания контекста может показаться, что Swift определяет тип параметра замыкания только по имени параметра или по содержимому тела. На практике имя параметра типа не задаёт, а одно тело иногда допускает несколько возможных типов.
Ошибки возникают, когда функция перегружена, ожидаемый тип не задан или выражение замыкания используется отдельно. В таких случаях компилятор может сообщить о невозможности вывести тип или о неоднозначности выбора перегрузки.
При вызове функции её параметр имеет ожидаемый тип. Если функция принимает замыкание от Int к String, то первый неаннотированный параметр замыкания получает тип Int, а результат должен быть совместим с String.
В этом примере number выводится как Int, а результат замыкания — как String. Вывод выполняется на этапе компиляции, поэтому внутри тела доступны только операции, допустимые для выведенного типа.
Контекст может поступать не только от параметра функции, но в данном сценарии главным источником является сигнатура принимающей функции. Если контекст конфликтует с телом замыкания, компиляция завершается ошибкой, а не выполняется динамическое преобразование типов.
У явной аннотации есть практический компромисс: она увеличивает объём записи, но делает намерение очевидным и помогает устранить неоднозначность. Особенно это полезно при перегруженных функциях или сложных generic-ограничениях.
В обработчике данных нужно передать преобразование элементов в функцию. Вариант с неявным выводом короче и хорошо читается, когда сигнатура функции очевидна. Его недостаток — при перегрузках или длинной цепочке вызовов сообщение компилятора может быть менее понятным.
Вариант с явными типами параметров лучше диагностируется и документирует границу API, но дублирует уже известную из сигнатуры информацию. Обычно выбирают вывод типов для локального простого кода, а явные аннотации — когда они устраняют неоднозначность или существенно улучшают читаемость.
Например, если существуют две перегруженные функции, принимающие замыкания с разными типами параметров, одного тела замыкания может быть недостаточно для выбора. Тогда явное указание типа параметра или явное приведение самого замыкания делает выбор однозначным и предотвращает зависимость от случайного контекста.
Вопрос: может ли имя параметра замыкания повлиять на его тип?
Нет. Имя — это локальный идентификатор, а не типовая информация. Тип приходит из ожидаемой сигнатуры, например из типа параметра функции или из явной аннотации.
Вопрос: что произойдёт, если тело замыкания использует операцию, несовместимую с выведенным типом?
Swift выдаст ошибку компиляции. Вывод контекстного типа не означает автоматического выбора любого подходящего типа или выполнения динамического приведения; тело проверяется относительно уже сформированного ожидаемого типа.
Вопрос: почему похожее замыкание иногда не компилируется при передаче в перегруженную функцию?
Перегруженные функции могут задавать разные ожидаемые типы замыкания. Пока компилятор не выбрал конкретную перегрузку, он может не знать типы неаннотированных параметров, а без этих типов — не суметь выбрать перегрузку. Явная аннотация параметра или результата добавляет недостающую информацию и разрешает неоднозначность.