Как lifetime-параметр структуры ограничивает срок жизни экземпляра, содержащего заимствованное поле?
Lifetime-параметр структуры связывает срок жизни экземпляра со сроком жизни данных, на которые он ссылается: экземпляр нельзя использовать дольше, чем доступно это заимствование. Он не продлевает жизнь данных и не управляет освобождением памяти, а только выражает проверяемое компилятором ограничение.
В Rust заимствование должно оставаться валидным без сборщика мусора и без ручного управления временем жизни ссылок. Поэтому компилятору нужно явно или неявно установить связь между существованием ссылки и существованием её владельца.
Lifetime-параметры решают эту задачу для пользовательских типов: структура может хранить ссылку, но её тип должен описывать, сколько эта ссылка потенциально действительна. Такой подход предотвращает висячие ссылки на этапе компиляции.
Представим структуру, хранящую ссылку на строковый срез. Если разрешить экземпляру пережить исходную строку, обращение к полю станет обращением к уже освобождённой памяти.
Обратная ошибка тоже возможна: если lifetime выбран слишком коротким, безопасное использование структуры будет запрещено раньше необходимого. Поэтому lifetime — это не время жизни объекта в смысле автоматического продления или освобождения, а ограничение допустимого периода использования ссылки внутри объекта.
Структура с заимствованным полем получает lifetime-параметр. Он означает: всякий экземпляр этой структуры обязан существовать не дольше, чем данные, доступные через соответствующую ссылку.
В примере View<'a> не владеет строкой: он хранит только ссылку. Пока view может использоваться, source не может быть уничтожен или изменён способом, несовместимым с активным заимствованием.
Lifetime структуры не является отдельным runtime-значением и не занимает память. После мономорфизации в машинном представлении ссылка обычно остаётся обычным указателем, а lifetime служит частью статической проверки типов.
Важно отличать lifetime параметра от 'static. Запись View<'static> означает, что ссылка действительна всю продолжительность программы, но не превращает обычную локальную строку в статическую. Большинство экземпляров имеют более короткий lifetime, выведенный из конкретного заимствования.
Если структура хранит несколько ссылок, разные lifetime-параметры позволяют выразить независимые ограничения. Один lifetime уместен только тогда, когда требуется связать сроки действия ссылок или когда такая связь действительно отражает контракт типа.
Компромисс состоит в том, что заимствующая структура не может самостоятельно продлить жизнь данных и обычно не может свободно перемещаться между контекстами с несовместимыми сроками. Если требуется независимое владение, вместо ссылки используют, например, String, Vec<T> или умный указатель с владением; это увеличивает стоимость копирования или выделения, зато устраняет зависимость от внешнего владельца.
Сервис форматирования получает большой буфер и создаёт набор представлений на его фрагменты. Хранить отдельные String для каждого фрагмента безопасно, но это требует копирования данных и дополнительных выделений памяти. Использовать сырые указатели быстрее по накладным расходам, но тогда проверка времени жизни и корректности доступа ложится на программиста.
Выбранное решение — структура представления со ссылкой и lifetime-параметром. Она не копирует текст, а компилятор гарантирует, что буфер не будет уничтожен, пока представления используются. Если представления должны пережить буфер или попасть в независимую очередь, структуру следует изменить на владеющую: например, хранить String или Arc<str>; это дороже по памяти, но устраняет внешний lifetime-контракт.
Нет. Lifetime только описывает уже существующее отношение доступности. Если исходная строка локальна, структура со ссылкой не может заставить её жить дольше области видимости; для этого нужно передать владение или выбрать другой владеющий тип.
Да, если новый контекст не требует, чтобы структура жила дольше данных, на которые она ссылается. Перемещается сама структура и копируется значение ссылки, но срок допустимого использования остаётся ограничен lifetime исходного заимствования. Если целевой контекст потенциально переживает источник, компилятор отклонит операцию.
Потому что она может владеть данными вместо заимствования, например хранить String, либо использовать типы, где lifetime скрыт внутри безопасной абстракции. Lifetime требуется указывать там, где тип непосредственно содержит ссылку или другой параметр типа, связанный с конкретным заимствованием; это позволяет компилятору проверить отношения между владельцем, ссылкой и экземпляром структуры.