ПрограммированиеRust systems разработчик

Может ли структура в Rust содержать ссылки на другие объекты? Какие ограничения по жизни таких ссылок и что произойдет при попытке вернуть из функции структуру с неполными сроками жизни ссылок?

Проходите собеседования с ИИ помощником Hintsage

Ответ

Структуры в Rust могут хранить ссылки на другие объекты через указание явных времён жизни (lifetimes) в определении структуры. Это требуется для того, чтобы компилятор мог проверить, что ни одна ссылка не станет недействительной. Вот пример:

struct Book<'a> { title: &'a str, author: &'a str, }

Здесь структура Book содержит две ссылки с одинаковым временем жизни 'a. Когда вы пишете функцию, возвращающую такую структуру, вы обязаны гарантировать, что все ссылки в ней будут действительны вне зависимости от внутренней логики функции:

fn book_factory<'a>(title: &'a str, author: &'a str) -> Book<'a> { Book { title, author } }

Если попытаться вернуть из функции структуру, где поля-ссылки указывают, например, на локальные переменные этой функции, произойдет ошибка компиляции, так как времени жизни ссылок недостаточно для безопасного доступа.

Вопрос с подвохом

Можно ли создать структуру, которая в одном из полей содержит ссылку (&str), а в другом — String? Почему это может быть проблемой?

Часто ошибочный ответ: "Да, можно, это безопасно".

На самом деле, если &str получено из String, а структура переживает этот String, ссылка станет висячей (dangling reference). Например:

struct Test<'a> { s1: &'a str, s2: String, } fn main() { let s = String::from("hello"); let t = Test { s1: &s, s2: s }; // t.s1, на самом деле, безопасен, только пока s2 (s) жив, но если s2 будет удалён первой — ошибка }

Примеры реальных ошибок из-за незнания тонкостей темы


История В одном проекте пытались возвращать из загружающей функции структуру, содержащую ссылку на временную строку, созданную внутри той же функции. Код скомпилировать не удалось, потребовалось значительное переписывание, чтобы убрать время жизни локальной переменной.


История Разработчик намеревался использовать структуру с ссылкой на элемент массива, созданного в функции, но после возвращения эта ссылка оказалась невалидной, что компилятор успешно предотвратил.


История В корпоративном проекте разработчики хранили ссылку &str на строку из другого объекта, который был удалён из коллекции раньше, чем сама ссылка — при последующем обращении к этой ссылке произошёл panic.