В каких случаях Rust продлевает время жизни временного значения, на которое взяли ссылку?
Rust может продлить время жизни временного значения до конца охватывающего блока, если ссылка создаётся в определённых формах инициализатора let. Это синтаксическое продление временного значения, а не общее правило для любых выражений со ссылками.
Обычная передача временного значения в функцию продлевает его жизнь только до конца текущего выражения. Если ссылка должна использоваться дольше, надёжное решение — явно сохранить владельца во внутренней переменной.
Rust управляет памятью без сборщика мусора, поэтому время жизни временных значений должно быть известно компилятору. При этом слишком короткая жизнь временных объектов сделала бы распространённую запись ссылки через let неудобной и потребовала бы явно разделять создание владельца и заимствование.
Продление времени жизни — компромисс между безопасностью и удобством. Оно не анализирует произвольное поведение программы, а применяется по ограниченным, предсказуемым синтаксическим правилам.
Временное значение обычно живёт до конца наименьшей области временного выражения, часто до конца текущего оператора. Если сохранить ссылку на такой объект и попытаться использовать её после уничтожения временного значения, возникла бы висячая ссылка.
Например, вызов метода над временной строкой может вернуть срез, но сама строка уничтожится в конце оператора. Ссылка после этого недействительна, поэтому Rust отклоняет такой код вместо потенциального обращения к освобождённой памяти.
В инициализаторе let Rust распознаёт некоторые продлевающие выражения. Наиболее важный случай — непосредственное создание ссылки на временное значение: временный владелец живёт до конца блока, в котором объявлена ссылка.
Здесь временный String живёт достаточно долго для использования text. Однако форма выражения имеет значение:
Этот вариант обычно отклоняется: ссылка создаётся результатом вызова метода, а не непосредственным продлевающим заимствованием. Временная строка заканчивает жизнь в конце оператора let.
Продление относится к конкретной временной области и не превращает значение в 'static. Оно также не распространяется автоматически на передачу временного объекта в функцию, возврат ссылки из функции или произвольное сохранение ссылки в структуре.
Следует отличать продление временной жизни от статического продвижения. При продвижении некоторые константоподобные выражения могут получить статическую область жизни; это отдельный механизм и применяется не ко всем типам и выражениям.
Практическое правило: если срок жизни должен быть очевиден или выражение сложное, сначала создайте владельца, затем заимствуйте его. Это делает зависимость ссылки от владельца явной и не зависит от тонких правил синтаксического продления.
При подготовке текстового представления разработчик пишет ссылку на результат метода временной строки. Компилятор отклоняет код, потому что временный String уничтожается раньше, чем предполагается использование среза.
Возможны такие варианты:
& — кратко, но применимо только к подходящей форме выражения;String — безопасно по времени жизни, но может потребовать дополнительного владения или копирования.Обычно выбирают явного владельца: он сохраняется в нужной области видимости, а ссылка берётся только после его создания. Такой вариант проще сопровождать, устойчивее к изменению выражения и не маскирует зависимость заимствования от владельца.
Нет, само по себе это не даёт времени жизни до конца блока. Временный объект обычно живёт до конца текущего оператора, поэтому функция может безопасно использовать ссылку во время вызова, но не может вернуть её для использования после завершения этого оператора.
Причина в том, что вызов функции не меняет владельца временного значения и не создаёт устойчивой области хранения. Если результатом должна быть долгоживущая ссылка, владелец должен существовать в вызывающей области или быть передан с подходящим временем жизни.
static?Нет. При продлении временный объект живёт только до конца конкретного блока или другой установленной временной области. После выхода из неё он уничтожается, и ссылка перестаёт быть действительной.
'static означает возможность жить всю продолжительность программы, а не просто дожить до конца блока. Смешение этих понятий приводит к ошибочному ожиданию, что ссылку на временный объект можно безопасно вернуть из функции или сохранить глобально.
Правила продления зависят от формы выражения, а не только от его логического смысла. Непосредственное заимствование в инициализаторе let может быть продлевающим, тогда как вызов метода, возвращающий ссылку, обычно создаёт ссылку из временного владельца в обычной временной области.
Поэтому изменение вроде замены прямого &владелец на владелец.метод() способно изменить результат проверки заимствований. Универсальное решение — назвать владельца отдельной переменной, после чего получить ссылку; тогда срок жизни определяется областью владельца, а не специальным синтаксическим правилом.