Подобно тому, как аннотации времени жизни применяются в функциях, они также могут применяться в структурах. Формальное применение аннотаций:
struct название_структуры<'аннотация> { поле_структуры: &'аннотация str, }
После названия структуры в угловых скобках идет название аннотации. Если поле структуры хранит ссылку, то после знака амперсанда &, но перед типом данных указывается название аннотации.
Сначала рассмотрим проблему, с которой мы можем столкнуться. Пусть у нас есть структура, поле которой представляет строковый слайс, то есть ссылку:
struct Person { name: &str, } fn main() { let tom = Person { name: "Tom" }; println!("{}", tom.name); }
Но при компиляции компилятор Rust укажет, что необходимо установить аннотации времени жизни для поля name
в структуре Person:
Теперь применим аннотации:
struct Person<'a> { name: &'a str, } fn main() { let tom = Person { name: "Tom" }; println!("{}", tom.name); // Tom }
Здесь структура применяет аннотацию 'a
. Применение аннотации означает, что объект структуры будет доступен пока доступна ссылка из
поля name. Что это значит? Рассмотрим следующий пример:
struct Person<'a> { name: &'a str, } fn main() { let mut tom; { let username = String::from("Tom"); tom = Person { name: username.as_str()}; println!("{}", tom.name); } tom.name = "Sam"; println!("{}", tom.name); }
Здесь переменная tom определена с ключевым словом mut
, чтобы теоретически можно было поменять значения ее полей.
Во вложенном блоке кода создается объект username
, который представляет тип String
. То есть время жизни этого объекта
ограничено вложенным блоком кода.
Далее полю name
объекта структуры присваивается строковый слайс, полученный с помощью метода as_str()
из объекта username.
tom = Person { name: username.as_str()};
После завершения вложенного блока кода мы пытаемся изменить значения поля name
- переменная tom же определена как изменяемая. Однако проблема в том,
что мы не можем использовать объект Person, представленный переменной tom, вне области видимости переменной username
. Соответственно при компиляции мы получим ошибку:
Мы могли бы исправать ситуацию, перенеся весь код использования объекта tom в область видимости переменной username:
struct Person<'a> { name: &'a str, } fn main() { let mut tom; { let username = String::from("Tom"); tom = Person { name: username.as_str()}; println!("{}", tom.name); // Tom tom.name = "Sam"; println!("{}", tom.name); // Sam } }
Либо создать новый объект структуры Person и присвоить его переменной tom:
struct Person<'a> { name: &'a str, } fn main() { let mut tom; { let username = String::from("Tom"); tom = Person { name: username.as_str()}; println!("{}", tom.name); } tom = Person { name: "Sam"}; println!("{}", tom.name); }
Правда, в данном случае мы уже будем работать с уже другим объектом.