Вызов обобщённой функции не даёт контекста ни в аргументах, ни в ожидаемом результате: почему Rust не выводит параметр типа?
Rust не выбирает произвольный тип для невыведенного параметра: компилятор должен получить его из ограничений, созданных аргументами, ожидаемым типом результата или явным указанием. Если таких ограничений нет, тип остаётся неизвестной переменной, поэтому компиляция завершается ошибкой. Тип можно задать явно через турбофиш-синтаксис или косвенно — аннотацией результата.
Вывод типов уменьшает количество повторяющихся аннотаций, но не отменяет необходимость однозначно определить тип каждой операции. Такой подход позволяет сохранять статическую проверку типов без требования указывать типы во всех выражениях.
Исходная проблема — баланс между краткостью кода и предсказуемостью компиляции. Rust выводит только то, что следует из доступного контекста, и не делает произвольных предположений, которые могли бы изменить смысл программы.
Рассмотрим обобщённую функцию, которая не получает значение типа T через параметры. Если результат вызова также не используется в контексте с известным типом, у компилятора нет ни одного ограничения, связывающего T с конкретным типом.
Выбор типа по умолчанию был бы небезопасен: разные типы могут иметь разные реализации трейтов, размеры, стоимость операций и поведение. Поэтому ошибка обнаруживается в месте вызова, а не скрывается за неявным выбором типа.
Rust строит систему ограничений для неизвестных типов. Тип параметра может быть выведен из типов аргументов, ожидаемого типа выражения, ограничений трейтов и других связанных выражений.
Если параметр типа не встречается в аргументах, это ещё не всегда означает ошибку: его может определить ожидаемый тип результата. Но когда отсутствуют и аргументный, и контекст результата, неизвестная переменная типа не получает решения.
Минимальный пример:
В первом вызове тип задан явно через ::<u32>. Во втором он выводится из аннотации Vec<String>, потому что ожидаемый тип результата создаёт необходимое ограничение.
Важно отличать параметр типа функции от параметра, для которого Rust поддерживает значение по умолчанию. Для обычного обобщённого вызова Rust не подставляет автоматически, например, i32 или String; отсутствие контекста остаётся ошибкой.
Явное указание типа повышает локальную читаемость и бывает необходимо в перегруженных или сложных обобщённых выражениях. Аннотация результата обычно удобнее, когда тип уже естественно следует из назначения переменной, но она может быть менее заметной при длинной цепочке вызовов.
В библиотеке есть обобщённая функция создания пустого контейнера. В месте вызова контейнер сразу передаётся в ветвление, где ожидаемый тип не задан, поэтому компилятор не может определить тип его элементов.
Возможны два решения. Явное указание параметра типа однозначно фиксирует контракт вызова, но увеличивает синтаксис. Аннотация переменной или возвращаемого значения сохраняет более декларативный стиль, однако требует, чтобы подходящий контекст действительно доходил до выражения.
Практичнее выбрать явное указание типа на границе сложного выражения, если оно предотвращает неоднозначность и делает намерение очевидным. В результате компилятор получает единственное решение, а дальнейшие операции над контейнером проверяются статически без динамического определения типов.
Нет. Rust может вывести его из ожидаемого типа результата. Например, если вызов функции возвращает Vec<T> и присваивается переменной типа Vec<String>, параметр T определяется как String.
i32?Правила вывода не должны зависеть от предположений о намерениях разработчика. Неявный выбор мог бы привести к другому набору реализаций трейтов, переполнениям, изменению размера значения или несовместимости с последующим кодом. Поэтому значения по умолчанию для некоторых литералов не являются универсальным правилом для параметров обобщённых функций.
as?Указание типа параметра через турбофиш-синтаксис сообщает компилятору, какой конкретный тип использовать в обобщённом вызове. Приведение через as преобразует уже типизированное значение в другой тип и может изменить его значение или способ представления. Это разные механизмы: первое устраняет неоднозначность вывода, второе выполняет преобразование.