Что произойдёт, если в операторе let Rust использовать шаблон, который может не совпасть со значением?
Программа не скомпилируется: обычный let требует неопровержимый шаблон, который гарантированно совпадает со значением. Шаблоны вроде Some(x) или Ok(value) могут не совпасть, поэтому для них нужны match, if let или let-else.
Разделение шаблонов на неопровержимые и опровержимые помогает Rust гарантировать инициализацию локальных переменных без скрытых ветвлений. Обычная привязка через let должна однозначно создать все указанные имена, тогда как условное сопоставление явно описывает случай несовпадения.
Такой подход продолжает общую модель Rust: потенциально неполные операции должны быть видимы в структуре программы, а не маскироваться под обычное присваивание.
Значение перечисления, например Option<T>, может находиться в нескольких вариантах. Шаблон Some(x) описывает только один из них, поэтому при несовпадении переменная x не была бы создана.
Если разрешить такой шаблон в обычном let, возникла бы неоднозначность: продолжать выполнение без переменной, аварийно завершать программу или неявно обрабатывать отсутствующий вариант. Rust запрещает этот выбор на уровне компиляции и требует явно описать поведение для всех случаев.
Неопровержимый шаблон совпадает с любым значением подходящего типа. Например, простое имя переменной, _ или структура с полями, каждое из которых тоже использует неопровержимый шаблон, гарантированно успешно сопоставляются.
Опровержимый шаблон может не совпасть. К ним относятся варианты перечислений, такие как Some(x), None, Ok(value) и Err(error), если рассматривается только один вариант. В обычном let они запрещены, потому что компилятор не может доказать, что связывание всегда произойдёт.
Для опровержимого шаблона используются конструкции с явной обработкой несовпадения:
if let продолжает выполнение по одной из ветвей, а match позволяет явно описать все варианты. let-else подходит, когда успешный вариант должен сразу создать переменную, а несовпадение должно завершить текущую область управления через return, break, continue или другую расходящуюся конструкцию.
Важное ограничение: let-else не предназначен для продолжения выполнения после несовпадения в той же точке. Его ветка else обязана завершать текущий поток управления; если нужно продолжить работу с альтернативным значением, обычно выбирают if let или match.
Функция получает необязательный параметр запроса и должна вернуть ошибку, если параметр отсутствует. Рассматривались три варианта: match с двумя ветвями, if let с последующей обработкой отсутствия и let-else.
match наиболее явен, но создаёт дополнительный уровень вложенности, если успешная ветвь содержит основную логику. if let удобен для локального условного действия, однако при обязательном параметре приходится отдельно организовывать выход из функции. Наиболее подходящим оказался let-else: успешное значение сразу связывается, а ошибочный случай явно завершает функцию.
В результате основной путь выполнения остаётся линейным, отсутствие параметра обработано явно, а компилятор гарантирует, что после конструкции переменная существует.
Вопрос: Является ли шаблон с несколькими вариантами перечисления неопровержимым?
Ответ: Да, если набор вариантов покрывает все возможные значения и сами вложенные шаблоны неопровержимы. Например, сопоставление всех вариантов перечисления в match может быть исчерпывающим, но это не превращает каждый отдельный шаблон варианта в неопровержимый: одиночный Some(x) всё равно может не совпасть. Для обычного let важна гарантированность конкретного шаблона, а не наличие где-то в программе обработки остальных вариантов.
Вопрос: Почему шаблон _ допустим в обычном let, хотя он не сохраняет значение?
Ответ: _ является неопровержимым шаблоном: он совпадает с любым значением и просто не создаёт переменную. Гарантия успешного сопоставления не зависит от того, используется ли результат дальше. В отличие от _, шаблон Some(_) всё ещё опровержим, потому что внешний вариант Some присутствует не у каждого значения Option.
Вопрос: Чем семантически отличается let-else от match, если оба могут обработать несовпадение?
Ответ: match выбирает одну из ветвей и может продолжить выполнение внутри каждой из них. let-else предназначен для успешного связывания значения в текущей области, а ветка несовпадения обязана расходиться и не возвращать управление к следующей строке после конструкции. Поэтому let-else выражает проверку предварительного условия, а match — полноценное ветвление по вариантам значения.