Перейти к содержимому

Match в Rust

match сравнивает значение со списком образцов (patterns) и выполняет код той ветки, которая подходит. Если ты пользовался оператором switch в других языках, считай match его гораздо более мощной версией. А если не пользовался — ничего страшного: это одна из самых полезных конструкций, и её стоит выучить пораньше.

fn main() {
let day = 3;
match day {
1 => println!("Понедельник"),
2 => println!("Вторник"),
3 => println!("Среда"),
4 => println!("Четверг"),
5 => println!("Пятница"),
_ => println!("Выходной"),
}
}

Вывод:

Среда
▶ Попробуй сам

_ — это ветка-заглушка: она подходит для всего, что не перечислено выше. match требует обработать все возможные значения, поэтому _ обычно стоит в конце и покрывает «всё остальное».

Несколько значений можно объединить в одну ветку через |:

fn main() {
let day = 6;
match day {
1 | 2 | 3 | 4 | 5 => println!("Будний день"),
6 | 7 => println!("Выходной"),
_ => println!("Такого дня нет"),
}
}
▶ Попробуй сам

Для чисел можно сопоставить целый диапазон через ..=:

fn main() {
let score = 85;
match score {
90..=100 => println!("A"),
75..=89 => println!("B"),
60..=74 => println!("C"),
_ => println!("F"),
}
}
▶ Попробуй сам

Как и if, match может давать значение:

fn main() {
let day = 6;
let kind = match day {
1 | 2 | 3 | 4 | 5 => "будний день",
6 | 7 => "выходной",
_ => "неизвестно",
};
println!("{kind}");
}
▶ Попробуй сам

match работает не только с числами. Он умеет сравнивать строковые срезы (&str) и символы, а диапазоны символов вроде 'a'..='z' работают так же, как числовые:

fn main() {
let command = "stop";
match command {
"start" => println!("Запускаю..."),
"stop" | "quit" => println!("Останавливаюсь."),
_ => println!("Неизвестная команда: {command}"),
}
let letter = 'k';
let kind = match letter {
'a' | 'e' | 'i' | 'o' | 'u' => "гласная",
'a'..='z' => "согласная",
'0'..='9' => "цифра",
_ => "что-то другое",
};
println!("'{letter}' — {kind}");
let name = String::from("Ferris");
match name.as_str() {
"Ferris" => println!("Привет, краб!"),
_ => println!("Привет, {name}!"),
}
}

Вывод:

Останавливаюсь.
'k' — согласная
Привет, краб!
▶ Попробуй сам

Здесь стоит заметить две вещи:

  • Порядок важен. 'a' тоже входит в 'a'..='z', но ветка с гласными стоит раньше, поэтому до ветки с согласными гласные не доходят. Rust всегда выбирает первую подходящую ветку.
  • Для String нужен .as_str(). Текст в кавычках, например "Ferris", — это &str. Если сопоставлять с ним String напрямую, Rust остановится с ошибкой error[E0308]: mismatched types ... expected String, found &str («типы не совпадают: ожидался String, а найден &str»). Вызов .as_str() даёт &str-представление строки String, с которым образцы уже могут сравнивать. (Чем они отличаются, рассказано в уроке Строки.)

Сравнение учитывает регистр: "Stop" не совпадёт с "stop". Если текст вводит пользователь, часто делают так: match input.to_lowercase().as_str().

Для простых проверок «да/нет» подойдёт и то и другое, но как только вариантов больше двух-трёх, match начинает выигрывать: он читается лучше длинной цепочки else if, а компилятор проверяет, что ты учёл каждый случай. Для одного условия «да или нет» по-прежнему лучше подходит if/else.

Сохрани номер месяца month (2). С помощью match как выражения вычисли, сколько в нём дней (високосные годы не учитываем), и выведи В месяце 2 дней: 28. Подсказка: в месяцах 1, 3, 5, 7, 8, 10 и 12 по 31 дню — объедини их в одну ветку через |.

Показать решение
fn main() {
let month = 2;
let days = match month {
1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
4 | 6 | 9 | 11 => 30,
2 => 28,
_ => 0, // такого месяца нет
};
println!("В месяце {month} дней: {days}");
}

Вывод:

В месяце 2 дней: 28
▶ Попробуй сам

Веб-серверы отвечают числом. Преврати code в короткое пояснение: 200 — это "OK", 404 — "Не найдено", любой другой код 400–499 — "Ошибка клиента", 500–599 — "Ошибка сервера", а всё остальное — "Неизвестно". Проверь на 503. Подсказка: точную ветку 404 поставь выше диапазона 400..=499, иначе до неё дело никогда не дойдёт.

Показать решение
fn main() {
let code = 503;
let meaning = match code {
200 => "OK",
404 => "Не найдено", // должна стоять перед диапазоном 400..=499
400..=499 => "Ошибка клиента",
500..=599 => "Ошибка сервера",
_ => "Неизвестно",
};
println!("{code}: {meaning}");
}

Вывод:

503: Ошибка сервера
▶ Попробуй сам
  • match сравнивает значение с образцами и выполняет подходящую ветку.
  • Нужно обработать все возможные значения — для этого есть заглушка _.
  • Значения объединяются через |, а диапазон задаётся через ..=.
  • Сопоставлять можно и текст &str, и символы char; для String используй .as_str().
  • match, как и if, можно использовать как выражение, которое даёт значение.

Проверь себя

1. Что делает образец _ в выражении match?

2. Что будет, если match обрабатывает не все возможные значения и в нём нет ветки _?

3. Как сопоставить несколько значений в одной ветке, например 1, 2 или 3?

Результат: 0 / 3