Какое правило Rust применяет к именам, связанным в альтернативных ветвях or pattern?

Какое правило Rust применяет к именам, связанным в альтернативных ветвях or-pattern?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

В альтернативных ветвях or-pattern (|) должны связываться одинаковые имена, причём с совместимыми типами и одинаковыми режимами связывания. Это позволяет использовать любое такое имя в теле единственной ветви match независимо от того, какая альтернатива совпала.

Исторический контекст

Альтернативные шаблоны нужны, чтобы объединять несколько вариантов с одинаковой обработкой и не дублировать тело ветви. Например, несколько состояний протокола могут приводить к одному действию.

Ограничение на связывания сохраняет предсказуемость: после сопоставления тело ветви должно иметь один и тот же набор доступных переменных при любом успешном варианте. Rust проверяет это на этапе компиляции, а не оставляет проблему на выполнение.

Постановка проблемы

Если разные альтернативы создают разные переменные, тело ветви нельзя однозначно проверить. Одна альтернатива могла бы предоставить имя, которого нет у другой, либо предоставить значение другого типа.

Такая неоднозначность привела бы к неявным условиям внутри тела match: доступность и тип переменной зависели бы от выбранной альтернативы. Rust запрещает это, поэтому ошибка обнаруживается сразу при компиляции.

Подробное решение

Каждая альтернатива or-pattern обязана связывать один и тот же набор имён. Для каждого имени должны совпадать его тип и режим связывания: например, все альтернативы должны связать значение по значению либо все — по ссылке.

enum Signal { Open(u16), Closed(u16), Paused(u16), } fn describe(signal: Signal) { match signal { Signal::Open(code) | Signal::Closed(code) => { println!("код: {code}"); } Signal::Paused(code) => println!("пауза: {code}"), } }

В первой ветви имя code существует в обеих альтернативах и имеет тип u16, поэтому тело ветви корректно. Если одна альтернатива связывала бы code, а другая — reason, такой шаблон был бы отвергнут.

То же правило действует для режимов владения. Нельзя в одной альтернативе получить значение по значению, а в другой — ссылку на него: тело ветви должно иметь единую семантику владения и единый тип переменной.

Это ограничение относится к согласованности связываний, а не к полной одинаковости самих шаблонов. Альтернативы могут проверять разные варианты перечисления или разные структурные формы, если их результирующие связывания совместимы.

Ситуация из практики

В обработчике сетевых событий состояния Open и Closed должны записываться одинаково, а Paused обрабатывается отдельно. Дублирование двух ветвей делает код длиннее и создаёт риск, что логика со временем разойдётся.

Возможный вариант — написать две отдельные ветви. Его плюс — максимальная явность, но минус — повторение тела и необходимость синхронно изменять обе ветви.

Другой вариант — изменить модель данных и заранее преобразовать несколько состояний в один общий вариант. Это может упростить обработку, но иногда теряет различие между исходными состояниями или усложняет API.

Оптимальным решением здесь является or-pattern с общим связыванием code. Он сохраняет различия вариантов в модели, устраняет дублирование и гарантирует компиляторной проверкой, что обе альтернативы предоставляют телу одинаковые данные.

Что кандидаты часто упускают

  1. Можно ли связать разные имена в разных альтернативах?

    Нет. Все альтернативы должны связывать одинаковый набор имён. Иначе тело ветви не имело бы гарантированного доступа к одному и тому же окружению при любом совпадении.

  2. Достаточно ли, чтобы имя совпадало, если типы значений различаются?

    Нет. Совпадение имени не устраняет различие типов. Тело ветви компилируется один раз, поэтому Rust требует, чтобы соответствующие связывания имели совместимый тип. Например, нельзя связать одно и то же имя с числом в одной альтернативе и со строкой в другой.

  3. Проверяет ли Rust все альтернативы во время выполнения?

    Нет. Во время выполнения выбирается одна подходящая альтернатива, а не выполняются все варианты по очереди как независимые действия. Символ | объединяет шаблоны сопоставления; он не означает выполнение двух ветвей. Требование одинаковых связываний нужно именно для того, чтобы после выбора любой альтернативы тело имело одинаковый статически проверенный интерфейс.