При присваивании неизменяемой ссылки другой переменной что именно копируется и почему исходное значение не дублируется?
Копируется сама ссылка — указатель на значение и связанная с ним информация, — но не объект, на который она указывает. Поэтому две переменные типа &T могут ссылаться на один объект без передачи владения и без клонирования данных.
Это безопасно, потому что через неизменяемую ссылку нельзя изменить объект. При этом копирование ссылки не продлевает её время жизни: обе ссылки остаются ограничены временем, в течение которого доступен исходный объект.
Подход Rust возник как способ обеспечить безопасность памяти без обязательного сборщика мусора и без ручного управления временем освобождения каждого объекта. Для этого владение отвечает за освобождение, а заимствование позволяет временно обращаться к объекту без передачи права владения.
Неизменяемые ссылки особенно важны для эффективного чтения: один объект можно передать нескольким потребителям без копирования его содержимого. Ограничение на изменение через такие ссылки предотвращает ситуацию, когда один код читает объект, пока другой меняет или перемещает его.
Представим большой объект, например конфигурацию или дерево разбора. Передача владения каждому обработчику сделала бы объект недоступным предыдущему владельцу, а клонирование потребовало бы дополнительной памяти и времени.
Передача ссылки решает проблему производительности, но создаёт требования к безопасности: ссылка не должна пережить объект, а доступ через неё не должен конфликтовать с изменением или перемещением этого объекта. Ошибочное представление о том, что копирование ссылки копирует данные или создаёт нового владельца, приводит к неправильному проектированию API.
Тип &T реализует Copy независимо от того, реализует ли T этот трейт. При копировании создаётся ещё одна ссылка на тот же объект; сам T не перемещается, не клонируется и не получает нового владельца.
В примере value и another указывают на одну строку. Переменная text сохраняет владение строкой после вызова, потому что в функцию передана ссылка, а не сама String.
Копируются не символы строки и не структура String, а дескриптор ссылки. Для обычной ссылки это концептуально адрес объекта; конкретное внутреннее представление зависит от типа ссылки и платформы. Для ссылок на динамически определяемые типы может копироваться также метаинформация, например длина среза или указатель на таблицу виртуальных методов.
Копирование ссылки не означает, что можно использовать её после окончания времени жизни объекта. Анализ заимствований проверяет, что каждая копия ссылки используется только пока живёт исходное значение. Кроме того, наличие активных &T ограничивает изменение и перемещение объекта: чтение безопасно только при сохранении неизменности объекта на период действия этих заимствований.
Важно отличать &T от &mut T. Неизменяемая ссылка является Copy, поскольку несколько читателей совместимы. Изменяемая ссылка не является Copy: её неявное копирование позволило бы создать несколько независимых путей записи к одному объекту и нарушить правило единственного изменяемого доступа.
Компромисс таков: ссылки позволяют избежать копирования данных, но требуют соблюдать ограничения времени жизни и доступа. Если нужна независимая копия объекта, необходимо явно клонировать значение, а если нужен новый владелец без копирования содержимого, следует передавать сам владеющий тип, например Box<T>, понимая последствия передачи владения.
В модуле конфигурации несколько функций должны прочитать одну большую структуру настроек. Вариант с передачей Config по значению потребовал бы передачи владения или явного клонирования; клонирование увеличило бы расход памяти и время обработки.
Вариант с &Config позволяет каждой функции получить собственную копию ссылки. Его плюс — отсутствие копирования структуры и сохранение владельца у вызывающего кода. Минус — функции не могут изменять конфигурацию через такую ссылку, а время использования ссылок связано с жизнью исходной конфигурации.
Передача изменяемой ссылки дала бы возможность обновления, но потребовала бы единственного активного изменяющего доступа и исключила бы одновременное чтение через обычные ссылки. Поэтому для этапа анализа выбран &Config: он точно выражает требование «только читать», сохраняет безопасность и не создаёт лишних копий данных.
Допустимо ли копировать ссылку на тип, который сам не реализует Copy?
Да. Реализация Copy у &T относится к самой ссылке, а не к T. Например, String не является Copy, но ссылку &String можно скопировать, потому что копируется только доступ к уже существующей строке.
Создаёт ли копирование ссылки новый срок жизни объекта?
Нет. Срок жизни объекта определяется его владельцем, а не количеством ссылок. Копия ссылки получает время использования, совместимое с исходным заимствованием, и не может легально пережить объект. Если владелец уничтожен, все ссылки на него становятся недействительными, поэтому Rust запрещает такие сценарии на этапе компиляции.
Почему две копии &T допустимы, а две копии &mut T — нет?
Две &T обеспечивают только чтение, поэтому их совместное существование не создаёт гонки записи или нарушения согласованности данных. &mut T даёт право изменять объект; свободное копирование такой ссылки создало бы несколько конкурирующих изменяющих доступов.
Поэтому &mut T передаётся с перемещением самой ссылки или временно пере-заимствуется, но не копируется как &T. Это ограничение является частью модели безопасной памяти и предотвращает небезопасные одновременные изменения даже в однопоточном коде.