В каких случаях Rust требует явных аннотаций времени жизни в сигнатуре функции, хотя ссылки уже присутствуют в параметрах?
Rust требует явных аннотаций, когда правила автоматического вывода времён жизни ссылок (lifetime elision) не могут однозначно определить связь между входными и возвращаемыми ссылками. Типичный случай — функция с несколькими ссылочными параметрами и возвращаемой ссылкой без получателя метода.
Аннотация не продлевает жизнь объекта и не выбирает её фактическую длительность. Она явно описывает отношение между временами жизни, которое проверяет заимствователь.
Времена жизни нужны Rust для предотвращения висячих ссылок без сборщика мусора и без ручного управления временем освобождения памяти. Компилятор должен доказать, что каждая ссылка остаётся действительной в течение всего периода её использования.
Записывать параметры времени жизни в каждой функции было бы избыточно, поэтому Rust ввёл правила elision: в часто встречающихся однозначных случаях компилятор подразумевает аннотации автоматически. При этом язык сохраняет явность там, где возможны разные корректные связи между ссылками.
Если функция принимает одну ссылку и возвращает ссылку, обычно очевидно, что результат связан с единственным входом. Но при двух входных ссылках результат может относиться к первой, ко второй или к некоторой общей области действия.
Компилятор не выводит это отношение произвольно из тела функции. Связь должна быть частью сигнатуры, чтобы вызывающий код видел контракт функции независимо от её реализации. Иначе можно было бы изменить тело функции и незаметно изменить правила допустимого использования результата.
Для функций Rust применяет три основных правила elision:
self назначается возвращаемой ссылке, если результат является ссылкой.Поэтому функция с одним ссылочным параметром обычно не нуждается в записи аннотации. Напротив, у свободной функции с двумя ссылочными параметрами и одной возвращаемой ссылкой правило не может выбрать источник результата.
Здесь явно указано, что результат связан только с left; время жизни _right независимо. Если функция могла бы вернуть любую из двух ссылок, сигнатура должна выразить соответствующее ограничение, например потребовать общий параметр времени жизни для обоих входов.
Аннотации описывают отношения, а не конкретные даты начала и окончания жизни. Фактическая область действия заимствования выбирается компилятором настолько короткой, насколько это безопасно, при соблюдении ограничений сигнатуры.
В библиотеке есть функция, выбирающая имя из двух конфигурационных источников. Источники могут иметь независимые области действия, а функция всегда возвращает значение из первого источника.
Можно связать оба параметра одним временем жизни. Это просто читается, но излишне ограничивает вызывающий код: первый и второй источники должны одновременно оставаться действительными, даже если второй фактически не используется.
Можно вернуть принадлежащий функции String. Такой вариант устраняет ограничения заимствования и подходит для долгоживущего результата, но требует выделения памяти и копирования данных.
Выбранный вариант — два независимых времени жизни и результат, связанный только с первым параметром. Он точно отражает поведение функции, не требует копирования и позволяет второму источнику жить независимо. Если реализацию позднее изменят так, чтобы результат мог происходить из обоих источников, контракт придётся пересмотреть явно.
Нет, для обычной функции это не заменяет явную сигнатуру. Правила elision основаны на форме сигнатуры, а не на анализе конкретной ветки тела. Поэтому при нескольких входных ссылках связь результата нужно записать явно, даже если реализация возвращает только один из параметров.
Это делает публичный контракт стабильным: вызывающий код проверяется по типу функции, а не по текущему исходному коду её тела.
Потому что аннотация задаёт только ограничение, а не создаёт объект и не продлевает его существование. Если возвращаемая ссылка помечена временем жизни 'a, исходный объект всё равно обязан быть действителен как минимум в течение 'a.
Попытка вернуть ссылку на локальную переменную будет отклонена: локальный объект уничтожается при выходе из функции, и никакая запись 'a не может отменить это правило.
self меняет требования к аннотациям в методе?Ссылка на self участвует в третьем правиле elision. Поэтому метод, возвращающий ссылку, часто может не указывать аннотацию: результат подразумевается связанным с временем жизни заимствования self.
Если у метода есть дополнительные ссылочные параметры и результат связан не с self, автоматического правила может быть недостаточно. Тогда нужно явно указать, с каким параметром связан результат; наличие self само по себе не доказывает, что возвращаемая ссылка происходит именно из него.