Определяет ли аннотация времени жизни порядок уничтожения значений, связанных ссылкой?
Нет. Аннотация времени жизни задаёт статическое ограничение: ссылка не может использоваться за пределами периода, когда её объект-источник гарантированно существует. Она не управляет порядком вызова Drop, не продлевает существование значения и не меняет правила уничтожения локальных переменных или полей.
Если уничтожение источника должно произойти раньше активной ссылки, такой код будет отклонён компилятором. Это следствие проверки корректности заимствования, а не команда аннотации времени жизни изменить порядок уничтожения.
Rust использует времена жизни как часть статической системы владения и заимствования, чтобы обеспечивать безопасность памяти без сборщика мусора. Исходная проблема состоит в необходимости разрешить эффективные ссылки без риска висячих указателей, двойного освобождения и использования уже уничтоженных данных.
Поэтому Rust разделяет две задачи: времена жизни проверяют допустимость использования ссылок, а владение и Drop определяют, когда значения уничтожаются. Смешивание этих задач приводит к неверному пониманию аннотаций.
Рассмотрим структуру, содержащую ссылку. Её параметр времени жизни описывает, как долго ссылка внутри структуры должна оставаться действительной. Однако из этого не следует, что структура будет уничтожена в конце этого периода или что объект, на который она ссылается, будет уничтожен каким-либо особым образом.
Неверное ожидание опасно в двух направлениях. Можно ошибочно считать, что аннотация продлевает жизнь объекта, либо пытаться с её помощью задать порядок уничтожения зависимых значений. В обоих случаях компилятор не даст требуемой семантики: он лишь отклонит использование, нарушающее гарантии безопасности.
Время жизни — это ограничение на допустимое использование ссылки. Если ссылка имеет время жизни 'a, это означает, что в каждом месте, где она используется, объект-источник должен быть ещё жив и доступен для соответствующего заимствования. Аннотация не является таймером и не представляет собой действие, выполняемое во время исполнения.
Порядок уничтожения задаётся другими правилами Rust: явным вызовом drop, областью видимости, порядком уничтожения локальных переменных и правилами для полей типов. Если значение-владелец нельзя уничтожить, пока существует активная ссылка на него, компилятор отклоняет такую последовательность операций либо требует сначала завершить заимствование.
В примере 'a связывает view.text с объектом text, но не приказывает уничтожить text после view и не задаёт длительность существования view. Безопасность обеспечивается тем, что text нельзя уничтожить или переместить способом, несовместимым с ещё активным заимствованием.
Важно отличать валидность ссылки от времени жизни значения как объекта. Ссылка может перестать использоваться раньше конца области видимости, и благодаря анализу неиспользуемых далее заимствований владелец иногда становится доступен раньше. Но это не означает, что аннотация сама завершила заимствование или выполнила уничтожение.
Аннотация также не может сделать самоссылочный объект безопасным: если объект перемещается, адрес его внутреннего поля может измениться, а lifetime не фиксирует адрес в памяти. Для управления порядком освобождения следует использовать владение, явное управление ресурсами или подходящие типы данных, а не параметры времени жизни.
Представим API, возвращающий представление над буфером. Один вариант — вернуть структуру со ссылкой и указать её связь с входным буфером. Это позволяет компилятору запретить уничтожение буфера до завершения допустимого использования представления, но не заставляет буфер жить дольше необходимого.
Второй вариант — хранить представление дольше буфера, рассчитывая, что аннотация 'a «удержит» буфер в памяти. Такой дизайн неверен: lifetime не владеет буфером и не предотвращает его уничтожение сам по себе. Если буфер пытаются уничтожить при ещё действующей ссылке, код не скомпилируется; если же владение передано другому компоненту, именно этот компонент должен отвечать за ресурс.
Третий вариант — копировать данные в независимое владение, например в String. Он устраняет связь с исходным буфером и позволяет результату жить отдельно, но требует дополнительных затрат памяти и копирования. Если копирование не нужно, выбранное решение — возвращать заимствованное представление с корректной связью времён жизни и явно соблюдать правила владения.
Дополнительный вопрос 1. Может ли аннотация времени жизни заставить значение уничтожаться позже?
Нет. Она только ограничивает множество допустимых программ с точки зрения ссылок. Чтобы значение жило дольше, оно должно находиться во внешней области видимости, быть передано владельцу с более длительным сроком или храниться в подходящей структуре; lifetime не меняет владение.
Дополнительный вопрос 2. Если владелец уничтожается, становится ли существующая ссылка автоматически безопасной до конца своей аннотированной жизни?
Нет. Уничтожение владельца делает ссылку недействительной, поэтому Rust не разрешает уничтожить владельца, пока это конфликтует с активным заимствованием. Аннотация описывает требование к валидности, а не гарантирует, что владелец будет сохранён независимо от действий программы.
Дополнительный вопрос 3. Можно ли через параметр времени жизни управлять моментом вызова Drop?
Нельзя. Drop вызывается по правилам времени жизни самого значения и его владельца, а не по имени параметра 'a. Параметры времени жизни обычно не имеют runtime-представления: после статической проверки они не становятся объектами, которые можно наблюдать или использовать для планирования освобождения ресурсов.