В типе со ссылкой на ссылку зачем внешней и внутренней ссылкам нужны разные времена жизни?
В типе &'outer &'inner T внешнее время жизни 'outer описывает, как долго можно пользоваться самой внутренней ссылкой, а 'inner — как долго действительна ссылка на значение T. Для безопасности Rust требует, чтобы внутреннее время жизни покрывало внешнее: 'inner должно длиться не меньше 'outer.
Это не означает, что внешняя ссылка продлевает жизнь T. Она лишь временно заимствует уже существующую ссылку, и это заимствование не может пережить значение, на которое указывает внутренняя ссылка.
Времена жизни в Rust позволяют проверять корректность ссылок во время компиляции без сборщика мусора и без неявного продления объектов. Для простых ссылок часто достаточно вывести ограничения автоматически, но вложенные ссылки имеют несколько независимых уровней заимствования.
Явное разделение времён жизни появилось как способ описать эти уровни без смешения срока действия самой ссылки и срока действия объекта, на который она в конечном счёте указывает.
Рассмотрим значение типа &'outer &'inner T. Здесь есть два заимствования:
T.Если внутренняя ссылка перестанет быть действительной раньше окончания 'outer, внешняя ссылка могла бы использовать уже недействительное значение ссылки. Это создало бы возможность обращения к освобождённому или недоступному объекту.
Обратная ситуация безопасна: сама внутренняя ссылка может существовать дольше, чем внешнее заимствование. После окончания 'outer внешняя ссылка исчезает, но исходная внутренняя ссылка и T могут продолжать существовать.
Для типа &'outer &'inner T действует отношение 'inner: 'outer. Оно читается как «'inner длится не меньше 'outer». Это ограничение относится не к продолжительности работы программы, а к допустимому включению одного времени жизни в другое.
Минимальный пример:
Функция временно заимствует внутреннюю ссылку на срок 'outer, но возвращает саму внутреннюю ссылку с временем 'inner. Поэтому результат потенциально может использоваться дольше внешнего заимствования, если исходная строка всё ещё существует.
Важно различать три сущности: внешнюю ссылку, внутреннюю ссылку и конечное значение T. 'outer ограничивает использование внешней ссылки, а 'inner — действительность внутренней ссылки относительно T. Ни одна аннотация не изменяет фактическое время жизни объекта и не перемещает его владельца.
Компилятор может выбрать для 'outer более короткий срок, чем максимально возможный срок существования внешней ссылки. Это позволяет временно передать &&T в функцию, не занимая внешнюю ссылку дольше необходимого. При этом выбранный 'outer всё равно не может превышать 'inner.
Представим API, который получает ссылку на переменную, содержащую уже подготовленную ссылку на текст. Например, внешний слой временно предоставляет доступ к конфигурационному полю, а внутренний слой должен вернуть сам текст.
Варианты решения:
&'outer str: безопасно, но результат искусственно привязан к сроку внешнего заимствования и может прожить меньше, чем исходный текст;&'inner str: сохраняет максимально полезную связь с исходным текстом, но требует, чтобы внутренняя ссылка была действительна на протяжении внешнего доступа;&&str на &str или передавать владельца строки: упрощает интерфейс, но может потребовать изменения архитектуры и передать лишнее владение.Обычно выбирают возврат &'inner str, если функция действительно лишь извлекает внутреннюю ссылку и не хранит внешнее заимствование. Это не продлевает жизнь строки, зато не ограничивает результат ненужным сроком действия промежуточной ссылки.
Нет. Для &'outer &'inner T требуется 'inner: 'outer, поскольку в течение всего 'outer нужно безопасно читать значение внутренней ссылки. Если внутренняя ссылка станет недействительной раньше, внешняя ссылка будет указывать на недействительную ссылочную величину.
'inner: 'outer, что внешняя ссылка автоматически получает время жизни 'inner?Нет. Это лишь верхняя граница совместимости. Фактическое внешнее заимствование может быть короче 'inner, например если функция использует внешнюю ссылку только в одном выражении. Аннотация описывает допустимую связь типов, а не заставляет компилятор продлевать заимствование до максимального срока.
Да, если возвращаемая ссылка связана с 'inner, а объект T и сама внутренняя ссылка действительны в течение 'inner. Внешняя ссылка нужна только для извлечения внутреннего значения; после копирования ссылочного значения результат уже не обязан зависеть от внешнего заимствования. Однако если внутренняя ссылка указывает на данные, срок жизни которых ограничен внешним контекстом, требование 'inner: 'outer и остальные ограничения вызова не позволят выдать результат с чрезмерно длинным временем жизни.