Разбор последствий: что именно гарантирует требование, чтобы обобщённый тип не содержал ссылок короче заданного времени жизни, и чего оно не гарантирует?
Такое требование гарантирует, что все ссылки, скрытые внутри обобщённого типа, действительны как минимум в течение указанного времени жизни. Оно ограничивает допустимые конкретные типы, подставляемые вместо параметра типа, но не продлевает жизнь принадлежащего значения и не заставляет его храниться дольше.
В Rust обобщённые типы могут содержать ссылки косвенно: например, вместо T можно подставить &str или структуру с ссылочным полем. Без проверки этой зависимости безопасное на вид обобщённое API могло бы сохранить тип, содержащий уже недействительную ссылку.
Ограничения времени жизни позволяют выразить такую зависимость на уровне типов. Компилятор проверяет её статически, не добавляя сборщик мусора и не продлевая существование значений во время выполнения.
Рассмотрим обобщённый контейнер, который логически может удерживать значение типа T в течение времени жизни 'a. Если T содержит ссылку, эта ссылка должна оставаться действительной не меньше 'a.
Ошибочное понимание приводит к двум противоположным выводам. Можно ошибочно решить, что ограничение продлевает жизнь временного значения, либо что оно требует от любого T физически существовать весь срок 'a. На самом деле оно проверяет только допустимость ссылок, входящих в состав типа.
Ограничение T: 'a означает: конкретный тип T не содержит ссылок с временем жизни короче 'a. Для T = String условие выполняется тривиально, поскольку String владеет своими данными и не содержит заимствований. Для T = &'short str оно выполнимо только тогда, когда 'short длится как минимум 'a.
Это ограничение относится к типу, а не к конкретному экземпляру. Значение типа T всё равно может быть перемещено или уничтожено раньше 'a, если API не хранит его там, где требуется такой срок. Ограничение не предотвращает drop, не продлевает заимствование и не превращает краткоживущую ссылку в долгоживущую.
Минимальная иллюстрация использует PhantomData, чтобы выразить логическую связь контейнера с типом T на срок 'a:
PhantomData<&'a T> не хранит ссылку во время выполнения, но сообщает компилятору о логической зависимости. Если T содержит заимствование, это заимствование должно быть совместимо с 'a; при этом сам объект Holder не получает права пережить значение, на которое T ссылается.
В современных обобщённых API подобное ограничение нередко выводится компилятором из полей или других bound-ов, поэтому его не всегда нужно писать явно. Однако смысл остаётся тем же: проверяется достаточная длительность внутренних заимствований, а не срок жизни владельца.
Допустим, библиотека создаёт типизированный контекст, который хранит пользовательский объект и передаёт его обработчику в течение некоторого контекста 'a. Возможны три подхода.
T без ограничения. Это проще по форме, но не позволяет компилятору доказать безопасность, если T содержит короткую ссылку.T: 'static. Это безопасно и упрощает API, но запрещает почти все заимствованные значения, даже если они гарантированно живут достаточно долго.T: 'a. Это выбранное решение: оно допускает как владеющие типы, так и заимствованные значения с подходящим сроком, не делая API излишне строгим.Результат — минимально необходимое ограничение. Контекст не получает возможности продлить жизнь вложенных ссылок, но компилятор не позволит использовать тип, чьи внутренние заимствования могут стать недействительными раньше контекста.
T: 'a препятствовать раннему уничтожению значения типа T?Нет. Оно описывает допустимость ссылок внутри типа, а не обязательную продолжительность существования экземпляра. Если значение передано по значению и больше не нужно, его можно уничтожить раньше окончания 'a; недопустимо лишь использовать его как живое значение там, где требуется соблюдение этой связи.
T: 'a обычно выполняется при любом 'a?Потому что у такого типа нет внутренних заимствований, которые могли бы стать недействительными. Владеющий тип вроде String хранит данные самостоятельно, поэтому его корректность не зависит от внешнего времени жизни. Это не означает, что объект String обязан жить дольше 'a.
T: 'a отличается от ограничения конкретной ссылки на 'a?Ограничение ссылки задаёт срок действия самой ссылки, например заимствования, используемого как &'a U. Ограничение T: 'a анализирует состав типа T и требует достаточного срока для всех ссылок, которые этот тип может содержать. Поэтому T может быть владеющим типом, ссылочным типом или сложной структурой с несколькими заимствованиями; проверка применяется к их совокупной зависимости от 'a.