Что меняется в семантике владения, когда значение сопоставляют с шаблоном _, а не связывают именем?
Шаблон _ сопоставляется со значением, но не создаёт связывания с ним. Поэтому при таком сопоставлении значение не перемещается только из-за самого шаблона, а исходное имя обычно остаётся доступным. Это отличается от связывания через обычное имя, которое может переместить значение, если его тип не реализует Copy.
Однако значение всё равно может быть уничтожено в зависимости от контекста. Например, временное значение, сопоставленное с _, будет отброшено после завершения соответствующего выражения.
Шаблоны Rust объединяют проверку структуры значения и связывание его частей. Для случаев, когда структуру нужно проверить, но само значение не требуется сохранять, используется wildcard-шаблон _.
Такой подход отделяет две операции: сопоставление значения и получение владения через имя. Это позволяет явно игнорировать данные без случайного перемещения ресурса.
Ошибка возникает, когда разработчик воспринимает _ как обычное имя переменной. Обычное связывание может переместить значение, после чего прежнее имя станет недоступным, а _ значения не связывает.
Особенно важно не путать _ с именем, начинающимся с подчёркивания. Шаблон _name всё равно создаёт связывание и может переместить значение; подчёркивание в начале лишь подавляет предупреждение о неиспользуемой переменной.
В шаблоне _ нет переменной, которую можно было бы использовать после сопоставления. Поэтому Rust не передаёт этому шаблону владение значением и не создаёт новое имя.
В отличие от него, связывание через имя анализируется по обычным правилам владения. Если значение некопируемое, например строка или вектор, получение его непосредственно в переменную шаблона обычно означает перемещение.
Важно учитывать контекст выражения. В конструкции сопоставления уже существующее значение не обязано перемещаться из-за _, но созданный непосредственно справа временный объект не может остаться доступным: после использования он будет уничтожен в обычный момент окончания времени жизни временного значения.
Минимальный пример:
В первом случае _ не перемещает text, поэтому имя доступно. Во втором случае _name является полноценным связыванием, и строка перемещается в него.
Компромисс состоит в том, что _ безопасен с точки зрения случайного перемещения, но не позволяет использовать или явно хранить сопоставленную часть значения. Если значение нужно сохранить для последующей работы, следует использовать имя и осознанно принять правила владения.
Обработчик получает объект запроса и должен проверить, что в нём присутствует полезная нагрузка, но не использовать её. Вариант с _ позволяет выполнить сопоставление без перемещения полезной нагрузки из исходного объекта. Вариант с _payload сохраняет payload в новом связывании, но может неожиданно переместить некопируемое поле и сделать исходный объект частично недоступным.
Если payload действительно не нужен, выбранным решением будет _: он выражает намерение игнорировать данные и не создаёт лишнего владельца. Если данные должны использоваться позднее, нужно связать их именем, а при необходимости — сопоставить ссылку, чтобы работать с заимствованием вместо перемещения.
Чем _ отличается от _name?
_ не создаёт переменную и не перемещает значение только фактом сопоставления. _name создаёт обычное связывание; начальное подчёркивание влияет главным образом на предупреждение о неиспользовании, но не отменяет владение и перемещение.
Означает ли _, что значение никогда не уничтожается?
Нет. _ лишь не связывает значение с именем. Если сопоставляется временный объект, он будет уничтожен по правилам времени жизни временных значений. Кроме того, значение, которым владел исходный объект, позже уничтожается вместе с этим объектом, если не было перемещено или явно отброшено раньше.
Всегда ли сопоставление с _ сохраняет доступность исходного имени?
Нет, это верно не для любого окружающего выражения, а для случая, когда _ сам не потребляет значение. Если значение уже передано по владению в функцию, возвращено из выражения или перемещено другой частью шаблона, исходное имя может стать недоступным по другой причине. _ не отменяет остальные правила владения; он только не добавляет собственного связывания.