Представьте, что изменяемую ссылку временно передали с более коротким временем жизни: почему исходная ссылка остаётся недоступной до окончания этого заимствования?
Более короткое время жизни временного заимствования ограничивает только период действия этого заимствования, но не отменяет правило эксклюзивности. Пока временная ссылка используется, исходная изменяемая ссылка не может одновременно применяться для другого доступа к тем же данным.
После последнего использования временной ссылки компилятор может завершить её заимствование, и исходная ссылка снова становится доступной. Это называется повторным заимствованием (reborrow), а не продлением или дублированием исходной ссылки.
Модель времён жизни в Rust решает задачу безопасной работы со ссылками без сборщика мусора. Компилятор должен предотвратить висячие ссылки, одновременный конфликтующий доступ и гонки данных ещё до запуска программы.
Для изменяемых ссылок одного контроля длительности недостаточно: даже ссылка, которая гарантированно не переживёт данные, может быть опасной при одновременном другом изменяемом или неизменяемом доступе. Поэтому правила времени жизни работают вместе с правилами владения и эксклюзивности.
Изменяемая ссылка предоставляет эксклюзивный доступ к объекту на период заимствования. Если временно передать её в другой контекст, компилятор должен гарантировать, что исходная ссылка не используется параллельно с этим временным доступом.
Иначе одна часть программы могла бы изменить данные через временную ссылку, пока другая часть читает или изменяет их через исходную. Даже если временная ссылка имеет более короткое время жизни, такое пересечение всё равно нарушает гарантию отсутствия конфликтующих доступов.
При передаче изменяемой ссылки компилятор обычно создаёт повторное заимствование исходного объекта на подходящий, часто более короткий срок. Исходная ссылка остаётся существовать, но временно считается занятой: использовать её напрямую нельзя до завершения повторного заимствования.
Ключевым является не момент выхода переменной из области видимости, а её последнее использование. Благодаря анализу неиспользуемых после этой точки ссылок компилятор может завершить короткое заимствование раньше конца внешнего блока.
В примере view создаёт короткое неизменяемое повторное заимствование данных, доступных через text. Вызов push разрешён после последнего использования view; если сначала изменить text, а затем снова использовать view, возникнет конфликт заимствований.
Аннотация времени жизни описывает допустимые отношения между ссылками, но не разрешает одновременные несовместимые доступы. Более короткая длительность делает повторное заимствование совместимым с внешним контекстом, однако на всём его протяжении действует эксклюзивность исходной изменяемой ссылки.
Допустим, обработчик получает изменяемую строку, временно передаёт её вспомогательной операции для чтения, а затем должен изменить строку. Возможны три подхода:
Выбранный вариант сохраняет владение у вызывающего кода, не создаёт лишних объектов и явно разделяет фазы чтения и изменения. Если ссылку нужно сохранить дольше и использовать одновременно с изменением исходных данных, простого изменения аннотации времени жизни недостаточно: потребуется изменить структуру алгоритма, владение данными или применить подход с внутренней изменяемостью, если он действительно соответствует требованиям безопасности.
1. Укорачивает ли повторное заимствование время жизни самой исходной изменяемой ссылки?
Нет. Исходная ссылка продолжает существовать и по-прежнему указывает на тот же объект. Ограничивается её доступность для использования: на период повторного заимствования она временно недоступна как источник нового конфликтующего доступа.
2. Почему после вызова вспомогательной функции исходную изменяемую ссылку обычно можно использовать снова?
Потому что компилятор может передать функции не саму ссылку навсегда, а временное повторное заимствование с областью действия, ограниченной вызовом. Когда функция возвращается и это заимствование больше не используется, конфликт заканчивается, поэтому исходный доступ восстанавливается.
3. Заставляет ли параметр с явно указанным временем жизни удерживать изменяемое заимствование до конца этого времени жизни?
Не обязательно. Аннотация задаёт отношения, которым типы должны соответствовать, но фактический срок конкретного заимствования определяется контекстом использования и ограничениями функции. Однако если ссылка возвращается, сохраняется в структуре или её время жизни связывается с другим результатом, компилятор может потребовать удерживать заимствование дольше; простая замена аннотации не отменяет это ограничение и не разрешает параллельный доступ.