При разборе шаблона с @ как Rust одновременно сохраняет всё сопоставленное значение и связывает его внутреннюю часть?
Оператор @ связывает с именем всё значение, которое успешно сопоставилось с подшаблоном, одновременно позволяя извлечь части этого значения обычными вложенными шаблонами. Например, whole @ Some(ref item) даёт владение всем Option через whole и заимствование его содержимого через item.
Режим владения внутренних связываний определяется обычными правилами шаблонов: без ref значение может быть перемещено или скопировано, а с ref создаётся ссылка.
Шаблоны Rust объединяют проверку структуры значения, извлечение его частей и создание связываний. Без @ для сохранения всего значения пришлось бы отдельно проверять условие, а затем повторно обращаться к исходному значению или дублировать логику сопоставления.
@ решает эту задачу декларативно: один шаблон одновременно выражает условие соответствия и нужные формы доступа к данным. Это особенно полезно для перечислений, где нужно знать и конкретный вариант, и всё исходное значение целиком.
Предположим, обработчику события нужно проверить, что событие содержит текст, получить ссылку на этот текст и передать всё событие другой функции. Простое деструктурирование извлекает поле, но не создаёт отдельного связывания для всего значения.
Неправильный выбор режима связывания может привести к перемещению строки из перечисления. После такого частичного перемещения исходное значение нельзя использовать целиком, если в нём остались перемещённые поля.
Форма имя @ шаблон означает: сначала значение должно соответствовать указанному шаблону, затем это же значение связывается с именем слева от @. Подшаблон справа может содержать дополнительные связывания для отдельных частей.
Здесь whole владеет всем значением Event, а text имеет тип &String и временно заимствует строку внутри whole. Поэтому оба связывания можно использовать в теле ветви: строка не была перемещена из перечисления.
Если вместо ref text использовать обычное связывание text, строка обычно будет перемещена из Event в text. Тогда whole станет частично перемещённым и его нельзя будет использовать целиком после обращения к перемещённому полю. Для типов, реализующих Copy, перемещения фактически заменяются копированием, поэтому такой конфликт владения может быть незаметен.
@ не означает копирование и не создаёт автоматически ссылку. Он лишь добавляет связывание всего значения; копирование, перемещение или заимствование определяются типом значения и режимом конкретного связывания. Условия в match также применяются после сопоставления с шаблоном и не меняют саму семантику @.
В обработчике протокольных сообщений нужно распознать сообщение с текстовым payload, записать исходное сообщение в журнал и передать текст в валидатор. Вариант с обычным деструктурированием удобен для валидатора, но теряет прямое связывание со всем сообщением; повторная передача исходной переменной может быть невозможна после перемещения строки.
Можно сопоставить сообщение по ссылке. Это сохраняет исходное значение доступным, но требует заранее работать с ссылкой и иногда усложняет сигнатуры вызываемых функций. Можно использовать @ вместе с ref, явно оставив всё сообщение во владении whole, а payload получить по ссылке.
Второй вариант выбран, когда ветви match уже получают значение во владение и нужно одновременно журналировать его и читать вложенное поле без копирования. Он не требует клонирования потенциально большой строки и явно показывает намерение сохранить владение целым сообщением; цена решения — необходимость внимательно выбрать режим заимствования.
@ копию значения?Нет. @ только добавляет связывание с целым значением. Если связывание требует перемещения, значение перемещается; если тип Copy, значение копируется; если используется ref или автоматический режим заимствования, создаётся ссылка.
Практическое следствие: нельзя рассчитывать на независимую копию исходного объекта только потому, что он связан слева от @. Для явной копии нужен Clone, а для совместного доступа без копирования — подходящий режим заимствования.
@ получить и целое значение, и перемещённое поле?Синтаксически это возможно не всегда без последствий, но владение остаётся подчинено правилам частичного перемещения. Если поле перемещено во внутреннее связывание, связывание всего объекта может стать частично перемещённым и использовать его как целое нельзя.
Чтобы сохранить возможность использовать весь объект, внутреннюю часть обычно связывают через ref, сопоставляют значение по ссылке либо используют Clone, если независимое владение действительно необходимо.
@ отличается от проверки условия в match?@ связывает значение во время структурного сопоставления и предоставляет его в теле соответствующей ветви. Условие if в охранном выражении лишь дополнительно проверяет уже сопоставленный шаблон и само по себе не создаёт связывание всего значения.
Поэтому @ подходит, когда всё значение нужно использовать в результате успешного сопоставления. Охранное выражение подходит для дополнительной логической проверки, но не заменяет связывание целого объекта и не расширяет покрытие шаблонов для проверки исчерпывающих вариантов.