Каждая ссылка в Rust имеет свое время жизни, которое обычно задается областью видимости или контекстом, в рамках которого ссылку можно использовать. И большинстве случаев Rust сам выводит для ссылки время жизни, опять же исходя из ее области видимости. Рассмотрим простейший пример:
fn main(){
let x;
{
let n = 2;
x = &n;
} // конец области видимости переменной n и ссылки &n
println!("x: {}", x);
}
Здесь во внутреннем блоке кода переменная x получает ссылку на данные переменной n: x = &n;
При завершении внутреннего блока кода память под переменную n освобождается, соответственно ссылка
&n становится недействительной, а переменная x теперь ссылается на несуществующие данные.
Однако чуть ниже идет попытка обратиться к данным переменной x, которые уже являются недействительными:
println!("x: {}", x);
К счастью компилятор Rust умееет отслеживать подробные ситуации, поэтому при компиляции мы получим ошибку:
error[E0597]: `n` does not live long enough --> main.rs:6:13 | 5 | let n = 2; | - binding `n` declared here 6 | x = &n; | ^^ borrowed value does not live long enough 7 | } // конец области видимости переменной n и ссылки... | - `n` dropped here while still borrowed 8 | 9 | println!("x: {}", x); | - borrow later used here error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0597`.
Если бы обе переменные были определены в одной области видимости, то такой проблемы не возникло:
fn main(){
let x;
let n = 2;
x = &n;
println!("x: {}", x); // x: 2
}
Либо, если бы переменной x только применялась в той области видимости, в которой действительно ее значение:
fn main(){
let x;
{
let n = 2;
x = &n;
println!("x: {}", x); // x: 2
}
}
Хотя в большинстве случаев Rust сам может вывести время жизни ссылки, в некоторых случаях это время необходимо указывать
явным образом. Так, рассмотрим другой пример - функцию, которая возвращает строковый слайс &str:
fn main(){
let message = get_message();
println!("message: {}", message);
}
fn get_message() -> &str {
"hello"
}
Здесь функция get_message() возвращает объект &str. Однако Rust не может определить время жизни
данной ссылки, поэтому при компиляции будет сгенерирована ошибка missing lifetime specifier:
error[E0106]: missing lifetime specifier --> main.rs:6:21 | 6 | fn get_message() -> &str { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | 6 | fn get_message() -> &'static str { | +++++++ help: instead, you are more likely to want to return an owned value | 6 | fn get_message() -> String { | ~~~~~~ error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0106`.
И в данной ситуации нам необходимо указать явным образом время жизни для возвращаемой ссылки.
Для установки времени жизни ссылки применяются аннотации, которые должны начинаться с апострофа ', например, аннотация 'a.
Аннотация помещается после символа амперсанда &, но до определения типа данных:
&i32 // обычная ссылка &'a i32 // ссылка с указанным временем жизни &'a mut i32 // изменяемая ссылка с указанным временем жизни
Так, изменим предыдущий пример, применив аннотации времени жизни:
fn main(){
let message = get_message();
println!("message: {}", message);
}
fn get_message<'a>() -> &'a str {
"hello"
}
После названия функции необходимо указать название аннотации. В данном случае аннотация называется 'a.
fn get_message<'a>()
Далее аннотация применяется к возвращаемому результату:
-> &'a str
Теперь программа будет успешно компилироваться и запускаться.
Стоит учесть, что аннотации времени жизни сами по себе они не имеют большого значения. В реальности они не меняют время жизни ссылки.
Их назначение - указать компилятору, как аннотации времени жизни соотносятся друг с другом. То есть
не существует в языке Rust некой встроенной аннотации 'a - это название мы даем аннотации сами.
Однако какое же время жизни будет у результата, который возвращается данной функцией? Если время жизни возвращаемой ссылки НЕ привязано к времени жизни параметров функции, то тогда время жизни возвращаемой ссылки соответствует времени жизни возвращаемого значения.
В данном случае в функции параметров нет, а возвращаемое значение - строковый литерал "hello". Строковые литералы сохраняются в памяти в течение всей работы программы, поэтому время жизни подобной ссылки - все время работы программы.