Как Rust определяет, перемещается ли значение при связывании с ним через шаблон?
По умолчанию связывание с шаблоном происходит по значению: Rust перемещает значение, если его тип не реализует Copy, и копирует его для типов Copy. Если сопоставление выполняется с ссылкой, механизм match ergonomics обычно формирует ссылочные связывания, поэтому исходное значение не перемещается.
Иными словами, результат определяется не самим match, а сочетанием вида шаблона, типа сопоставляемого выражения и режима связывания. Явное заимствование через ссылку позволяет проверить или извлечь данные без потери владения.
Pattern matching в Rust предназначен для безопасного разбора перечислений, структур и кортежей. В языках без строгого владения извлечение поля часто не требует отдельного рассуждения о времени жизни значения, но в Rust такой подход должен учитывать, кто владеет данными.
Связь шаблонов с семантикой владения позволяет компилятору предотвращать неявные глубокие копирования и использование перемещённых значений. При этом сопоставление со ссылками сохраняет удобный синтаксис и не заставляет разработчика вручную копировать данные только ради проверки их структуры.
Рассмотрим значение перечисления с полем String. Если сопоставить его напрямую и связать поле по значению, строка может быть перемещена в новую переменную. После этого исходное значение нельзя использовать целиком, а при частичном перемещении нельзя обращаться к перемещённому полю.
Без понимания этого правила разработчик может получить ошибку компиляции в месте, которое выглядит как обычная проверка. Обратная ошибка тоже возможна: постоянное клонирование для обхода перемещения создаёт лишние аллокации и копирование данных.
В шаблоне обычное имя вроде value является связыванием по значению. Для некопируемого типа это означает move, для типа, реализующего Copy, — побитовую копию значения согласно правилам Copy.
Если сопоставляемое выражение является ссылкой, Rust применяет автоматический режим связывания: шаблон может разбирать объект за ссылкой, а связанные имена получают ссылочный тип. Например, при сопоставлении &Option<String> поле text обычно имеет тип &String, а не String.
Здесь &message передаёт в match ссылку. Поэтому text — ссылка на строку, а message сохраняет владение и доступно после сопоставления.
При сопоставлении самого message шаблон Message::Text(text) связывает text по значению. Для String это перемещение, поэтому после такого сопоставления использование исходного значения целиком может стать недопустимым. Если нужно владеть извлечёнными данными, перемещение полезно; если требуется только чтение, предпочтительнее сопоставление со ссылкой.
Явные конструкции вроде ref также задают заимствующее связывание в подходящих шаблонах, но в современном Rust чаще проще передать в match ссылку заранее. Для изменяемого доступа используется изменяемая ссылка, а не клонирование значения.
Важно различать перемещение поля и перемещение всего объекта. Из структуры можно переместить отдельное некопируемое поле, после чего сама структура становится частично перемещённой: разрешены операции с неперемещёнными полями, но не использование всей структуры как единого значения.
Сервис получает сообщение с большим текстовым payload и должен определить его тип, записав метаданные в журнал, а затем передать исходное сообщение обработчику. Вариант с сопоставлением по значению прост, но перемещает String; вариант с clone сохраняет исходное сообщение, однако копирует весь payload и может существенно увеличить расход памяти.
Сопоставление со ссылкой решает задачу без копирования: обработчик получает только нужные сведения для чтения, а исходное сообщение остаётся владельцем текста. Если на следующем этапе действительно требуется передать текст во владение другому компоненту, его можно переместить отдельно в явно выбранной точке.
Такой выбор разделяет две операции: анализ структуры выполняется через заимствование, а передача владения — через осознанное перемещение. Это обычно даёт меньше аллокаций и делает границы владения заметными в коде.
Нет. Для типа, реализующего Copy, происходит копирование, а не перемещение. Кроме того, при сопоставлении со ссылкой связывание обычно становится ссылочным благодаря match ergonomics, поэтому некопируемое поле также не покидает исходное значение.
Option<String> и &Option<String>?При сопоставлении Option<String> по значению извлечение String перемещает строку, если она не используется через ссылку или не копируется. При сопоставлении &Option<String> шаблон разбирает ссылочное представление, и поле связывается как ссылка; исходный Option<String> остаётся доступным.
Разница находится на уровне входного выражения, а не названия шаблона. Один и тот же визуально похожий шаблон может дать разные типы связанных переменных в зависимости от того, передано значение или ссылка.
Частично. Rust отслеживает частичное перемещение: доступ к независимым полям, которые не были перемещены, может остаться разрешённым, но использование всей структуры, её автоматическое уничтожение в некоторых формах или обращение к перемещённому полю запрещаются.
Это ограничение защищает корректность освобождения памяти: программа не должна попытаться считать, что перемещённое поле всё ещё находится внутри исходного объекта. Если нужно сохранить возможность полного использования структуры, следует сопоставлять её по ссылке либо извлекать данные способом, который явно соответствует владению.