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