Сопоставление с образцом: match
match — мощный оператор выбора по образцу, который компилятор заставляет делать исчерпывающим.
match сопоставляет значение с набором образцов и выполняет ветку первого совпавшего; компилятор требует, чтобы были покрыты все возможные случаи.
Базовый match
match сравнивает значение по очереди с образцами и выполняет первую подходящую ветку. Это как switch из других языков, но гораздо умнее.
fn main() {
let n = 3;
let name = match n {
1 => "один",
2 => "два",
3 => "три",
_ => "много", // _ — образец «всё остальное»
};
println!("{name}");
}Вывод:
три
match — это выражение: он возвращает значение, которое можно сразу присвоить переменной. Подчёркивание _ ловит все непокрытые случаи.
Исчерпывающность — суперсила match
Ключевое отличие от switch: Rust требует, чтобы match покрывал все возможные значения. Забыли вариант перечисления — код не скомпилируется. Это бесценно: добавили новый вариант в enum — компилятор перечислит все места, где его надо обработать.
enum Status {
Active,
Paused,
Stopped,
}
fn label(s: Status) -> &'static str {
match s {
Status::Active => "работает",
Status::Paused => "на паузе",
Status::Stopped => "остановлен",
// забыли ветку — ОШИБКА компиляции: pattern not covered
}
}
fn main() {
println!("{}", label(Status::Paused));
}Вывод:
на паузе
Извлечение данных из образца
match умеет распаковывать данные прямо в ветке. Это идеально сочетается с перечислениями, несущими данные, и с Option.
fn main() {
let maybe = Some(42);
match maybe {
Some(x) => println!("значение: {x}"), // x связывается с содержимым
None => println!("пусто"),
}
}Вывод:
значение: 42
Диапазоны и несколько образцов
В одной ветке можно перечислить несколько образцов через | или задать диапазон через ..=.
fn main() {
let score = 75;
let grade = match score {
90..=100 => "отлично",
70..=89 => "хорошо",
50..=69 => "удовлетворительно",
_ => "плохо",
};
println!("{grade}");
}Вывод:
хорошо
Охранные условия
К образцу можно добавить дополнительное условие через if — это охранное выражение (guard).
fn main() {
let pair = (0, -5);
let msg = match pair {
(0, y) if y < 0 => "на оси Y ниже нуля",
(0, _) => "на оси Y",
(x, 0) if x > 0 => "на оси X справа",
_ => "где-то ещё",
};
println!("{msg}");
}Вывод:
на оси Y ниже нуля
Итог
match— выражение выбора по образцу;_ловит остальные случаи.- Компилятор требует исчерпывающности: все варианты должны быть покрыты.
- Образцы распаковывают данные, поддерживают диапазоны
..=, альтернативы|и охранныеif.