Каждая ссылка в 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 умееет отслеживать подробные ситуации, поэтому при компиляции мы получим ошибку:
Если бы обе переменные были определены в одной области видимости, то такой проблемы не возникло:
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:
И в данной ситуации нам необходимо указать явным образом время жизни для возвращаемой ссылки.
Для установки времени жизни ссылки применяются аннотации, которые должны начинаться с апострофа ', например, аннотация '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". Строковые литералы сохраняются в памяти в течение всей работы программы, поэтому время жизни подобной ссылки - все время работы программы.