Объясните механизм отношения «время жизни 'a дольше 'b»: какой вывод о допустимом использовании ссылки следует из этой связи?
Связь 'a: 'b означает, что время жизни 'a не короче 'b: ссылка, действительная в течение 'a, может безопасно использоваться там, где требуется действительность в течение 'b. Это не продлевает ни одну область действия и не делает времена жизни равными.
В Rust времена жизни нужны для статического контроля заимствований. Компилятор должен доказать, что каждая ссылка не переживает значение, на которое она указывает, иначе возможна висячая ссылка.
Одних локальных областей действия недостаточно, когда функция или тип работают с несколькими ссылками. Поэтому аннотации времени жизни позволяют явно выразить отношения между ними, включая отношение «одна ссылка живёт не меньше другой».
Предположим, функция должна вернуть ссылку, допустимую только в течение короткого этапа работы, но получает другую ссылку от объекта, живущего дольше этого этапа. Без связи между временами жизней компилятор не может обосновать, что возвращаемая ссылка безопасна.
Неверное решение — считать, что аннотация 'a сама по себе продлевает существование данных. На самом деле она только добавляет ограничение, которое фактические области действия должны удовлетворять; если исходное значение уничтожено раньше, программа не скомпилируется.
Запись 'a: 'b читается как «'a переживает 'b» или «'a не короче 'b». Следовательно, значение, доступное в течение 'a, можно использовать в контексте, которому достаточно срока 'b.
Это похоже на безопасное сокращение времени жизни ссылки. Ссылка с более долгим допустимым сроком может быть использована как ссылка с более коротким сроком, но обратное преобразование небезопасно: короткая ссылка может указывать на данные, которые уже исчезнут.
Минимальный пример:
Параметр long действителен в течение 'a, а результат объявлен как действующий в течение 'b. Ограничение 'a: 'b доказывает, что long можно безопасно рассматривать как ссылку с более коротким сроком. После выхода из внутреннего блока результат нельзя использовать, даже если owner продолжает существовать.
Связь не требует, чтобы фактические времена жизни были одинаковыми. 'b может быть существенно короче 'a; это обычный и полезный случай. Кроме того, аннотация задаёт допустимое отношение типов, а не заставляет разработчика вручную управлять длительностью заимствования.
Ограничение может оказаться невыполнимым в месте вызова. Если источник, соответствующий 'a, уничтожается раньше, чем требуется для 'b, компилятор отклонит программу. Тем самым проверяется не только сигнатура, но и реальные области действия конкретных значений.
Рассмотрим обработчик, который получает долговечный буфер конфигурации и создаёт краткоживущий результат для одного шага разбора. Результат может ссылаться на буфер, но не должен становиться доступным дольше, чем длится этот шаг.
Возможны такие решения:
'a: 'b. Это сохраняет работу без копирования и позволяет использовать результат только в безопасном коротком контексте.Обычно выбирают третий вариант, когда копирование дорого, а результат действительно не должен покидать краткий этап обработки. Если результат должен передаваться дальше независимо от исходного буфера, правильнее изменить модель владения и вернуть собственные данные, а не ослаблять проверку времён жизни.
Означает ли 'a: 'b, что 'a и 'b — конкретные фиксированные промежутки времени?
Нет. Это параметры, выбираемые компилятором для конкретного использования, а не таймеры и не значения, доступные во время выполнения. Связь задаёт отношение между допустимыми сроками действия ссылок: 'a должен быть не короче 'b.
Можно ли из ссылки с временем жизни 'b получить ссылку с временем жизни 'a, если объявлено 'a: 'b?
Нет. Направление имеет значение. Из более долгого срока можно безопасно перейти к более короткому, потому что данные гарантированно сохранятся весь короткий период. Обратный переход потребовал бы доказать, что исходная ссылка продолжит действовать после 'b, а условие 'a: 'b этого не доказывает.
Что произойдёт, если источник действительно живёт дольше, но компилятор не видит нужной связи в типах?
Код может не пройти проверку, даже если разработчик понимает, что конкретный вызов безопасен. Компилятор использует доказательства из сигнатур, ограничений и областей действия, а не намерения программиста. Нужно выразить требуемую связь в типах либо изменить API; добавление аннотации без фактического выполнения ограничения не поможет.