Разбор последствий: означает ли одна и та же аннотация времени жизни у двух входных ссылок, что вызывающий обязан предоставить ссылки с одинаковым сроком действия?
Нет. Одна и та же аннотация, например 'a, означает, что функция рассматривает обе ссылки в рамках одного общего времени жизни, но фактические исходные сроки действия ссылок могут различаться. При вызове компилятор выбирает такую область 'a, в течение которой обе ссылки гарантированно действительны; обычно это не больше короткого из исходных сроков.
Поэтому длинную ссылку можно передать вместе с короткой. Общая аннотация не продлевает короткую ссылку и не делает ссылки фактически равными по длительности.
В Rust время жизни нужно описывать, чтобы компилятор мог доказать: ссылка не будет использована после уничтожения данных, на которые она указывает. Эта проверка должна работать статически, без сборки мусора и без добавления скрытого управления временем жизни объектов.
Аннотации времени жизни появились как способ явно выразить отношения между ссылками в интерфейсе функции, когда одних типов недостаточно. Они не управляют памятью и не продлевают существование значений, а только задают ограничения для проверки заимствований.
Рассмотрим функцию, которая выбирает одну из двух строк. Если она может вернуть любую из входных ссылок, возвращаемая ссылка должна быть действительна столько же, сколько действительна каждая возможная выбранная ссылка.
Если одна входная строка живёт дольше другой, безопасный срок для результата ограничен более коротким временем. Попытка использовать результат после уничтожения короткоживущей строки должна быть отклонена компилятором.
Важно отличать это от требования передавать ссылки с одинаковыми исходными сроками. Такое требование было бы слишком сильным: достаточно, чтобы обе ссылки одновременно были действительны в момент использования внутри функции.
Одинаковое имя времени жизни связывает ссылки логически. Для функции с двумя параметрами &'a str компилятор ищет конкретное 'a, подходящее обеим ссылкам. Это общее время жизни может быть короче полного времени жизни любой из них.
Аннотация не означает, что исходные ссылки были созданы одновременно или имеют идентичные области действия. Она означает, что функция получает допустимые представления обеих ссылок на общей области, достаточной для выполняемых операций.
Например:
Здесь persistent живёт дольше temporary, но вызов допустим. Для chosen выбирается срок, в течение которого действительны обе ссылки; после завершения внутреннего блока результат нельзя было бы безопасно использовать, поскольку он потенциально ссылается на temporary.
Если параметры имеют разные аннотации, например &'a str и &'b str, это означает отсутствие заявленной связи между их сроками. Такой вариант подходит, когда функция обрабатывает ссылки независимо. Но если результат может быть заимствован из одного из параметров, одной независимости недостаточно: потребуется дополнительное отношение, связывающее срок результата с подходящим входом, либо другой дизайн API.
Практическое следствие: одинаковая аннотация ограничивает возможный срок совместного использования и особенно важна для возвращаемых ссылок, структур и других значений, сохраняющих заимствование. При этом она не заставляет вызывающий код искусственно продлевать короткую ссылку — это невозможно сделать безопасно.
В библиотеке есть функция выбора наиболее подходшего имени из двух входных строк. Она возвращает ссылку, поэтому результат может указывать на любую из них.
Рассматривались варианты:
String. Это упрощает управление сроками, но требует копирования данных и может увеличить стоимость вызова.Выбран третий вариант. Длинный и короткий вход можно передать вместе, но полученный результат используется только пока действительны оба. В итоге API сохраняет отсутствие копирования и не обещает вызывающему коду срок, который невозможно гарантировать.
Означает ли общая аннотация, что компилятор выбирает полный срок жизни длинной ссылки?
Нет. Параметр времени жизни является параметром ограничений, а не обещанием использовать максимальный срок. Для двух ссылок общий срок должен подходить обеим, поэтому он может быть сокращён до их пересечения. Это особенно заметно, когда одна ссылка указывает на локальное значение, существующее меньше другой ссылки.
Можно ли использовать результат функции с общей аннотацией после завершения области короткой входной ссылки?
Нет, если результат потенциально ссылается на эту короткую ссылку. Сигнатура гарантирует лишь срок, общий для обоих входов. Даже если фактическая ветка функции вернула длинную ссылку, вызывающий код обычно не может получить более точную гарантию из такой общей сигнатуры: контракт обязан быть безопасным для любого допустимого результата.
Зачем разделять аннотации входных ссылок, если во время вызова обе всё равно должны быть живы одновременно?
Совместная доступность во время вызова не равна объявленной связи их сроков. Разные аннотации позволяют типовой системе не считать один срок зависимым от другого, что важно для более сложных сигнатур, возвращаемых ссылок и значений, которые сохраняют только одно из заимствований. Общая аннотация нужна, когда контракт действительно требует общего срока, например результат может быть выбран из любого входа; иначе она может выразить более сильную связь, чем требуется API.