Перейти к основному содержимому
  1. Rust/

Продвинутый Pattern Matching в Rust: деструктуризация, @-связывание и match guards

862 слова·5 минут· loading · loading · · ·Rust-middle Черновик
О Rust - Эта статья часть цикла.
Статей прочитано 0/58
0%
📚 Введение и дополнительные материалы
🟢 Начальный уровень (Rust-basic)
Не прочитана
🔵 Средний уровень (Rust-middle)
41 Продвинутый Pattern Matching в Rust: деструктуризация, @-связывание и match guards (текущая)
Не прочитана

Введение
#

Сопоставление с образцом (Pattern Matching) — одна из самых выразительных и сильных сторон синтаксиса Rust. В отличие от банального оператора switch из других языков программирования, паттерн-матчинг в Rust умеет разрушать сложные структуры данных, проверять диапазоны, связывать переменные «на лету» и проверять динамические условия.

В прошлых статьях мы уже знакомились с базовым синтаксисом rust-enums и управляющими конструкциями ветвления rust-conditionals.

В этой статье мы погрузимся в продвинутые техники Pattern Matching: деструктуризацию глубоких структур, связывание @, охранные выражения (Match Guards) и цепочки if let.


1. Принцип полноты (Exhaustiveness) и деструктуризация
#

Ключевое правило сопоставления в Rust — полнота проверок (Exhaustiveness). Компилятор требует, чтобы ваше выражение match обрабатывало все возможные состояния входного типа.

Pattern Matching позволяет выполнять глубокую деструктуризацию — одномоментно извлекать значения из вложенных структур, кортежей и сложных вариантов enum:

let Person { name, address: Address { street, city } } = person;

2. @-связывание и Охранные выражения (Match Guards)
#

Иногда при проверке значения на вхождение в диапазон (например, 1..=10) вам нужно одновременно сохранить это значение в переменную. Для этого используется оператор @ (Binding Pattern):

num @ 1..=10 => println!("Число {num} в диапазоне 1..10"),

А если синтаксический шаблон требует дополнительной логической проверки, на помощь приходят Match Guards — дополнительные if-условия прямо внутри ветки match:

Signal::Move { x, y } if x == y => println!("Диагональное перемещение"),

Изучите пошаговый пример деструктуризации и match guards в блоке ниже:

Деструктуризация, @-связывание и Match Guards
Шаг 1/2
 1// Шаг 1: Глубокая деструктуризация структур и связывающие шаблоны (@)
 2struct Address {
 3    street: String,
 4    city: String,
 5}
 6
 7struct Person {
 8    name: String,
 9    address: Address,
10}
11
12fn main() {
13    let person = Person {
14        name: String::from("Алексей"),
15        address: Address {
16            street: String::from("Ленина"),
17            city: String::from("Москва"),
18        },
19    };
20
21    // 1. Извлечение полей из вложенной структуры за одно действие:
22    let Person { name, address: Address { street, city } } = person;
23    println!("Имя: {name}, Город: {city}, Улица: {street}");
24
25    // 2. Использование @-связывания для сохранения значения при проверке диапазона:
26    let val = 15;
27    match val {
28        num @ 1..=10 => println!("Число {num} в диапазоне от 1 до 10"),
29        num @ 11..=20 => println!("Число {num} в диапазоне от 11 до 20"),
30        _ => println!("Другое число"),
31    }
32}
33

1. Деструктуризация и @-связывание

  • Шаблоны позволяют разбирать вложенные структуры и перечисления за один шаг без временных переменных.
  • Оператор @ сохраняет привязанное значение в переменную одновременно с проверкой диапазона или шаблона.

3. Цепочки if let (let_chains) и цикл while let
#

Когда вам требуется обработать строго один вариант шаблона из rust-collections-overview, конструкция match может выглядеть избыточно.

В современном Rust поддерживаются цепочки if let (let_chains) с оператором &&, позволяющие связывать несколько шаблонов в одно лаконичное условие:

if let Some(res) = result && let Ok(val) = res && val > 10 {
    println!("Успешно извлечено: {val}");
}

А для построчной или поконтейнерной обработки элементов итераторов из статьи rust-iterators-deep-dive используется конструкция while let:

while let Some(val) = iter.next() {
    println!("Обработан элемент: {val}");
}

Попробуйте выполнить пример с цепочками if let и циклом while let:

Цепочки if let и цикл while let
Шаг 1/2
 1// Шаг 1: Комбинирование условий в цепочках if let (let_chains)
 2fn main() {
 3    let result: Option<Result<i32, &str>> = Some(Ok(42));
 4
 5    // Цепочка if let с комбинированием условий через оператор &&:
 6    if let Some(res) = result && let Ok(val) = res && val > 10 {
 7        println!("Успешно извлечено значение больше 10: {val}");
 8    }
 9}
10

1. Цепочки if let (let_chains)

  • В современных версиях Rust можно объединять несколько сопоставлений let и булевых выражений через &&.
  • Это избавляет от необходимости писать несколько вложенных блоков if let.

Проверь свои знания!
#

Пройдите короткий тест по продвинутому Pattern Matching:

Статья прочитана
Пожалуйста, оцените насколько статья была вам полезна и понятна
Цикл статей
О Rust - Эта статья часть цикла.
Статей прочитано 0/58
0%
📚 Введение и дополнительные материалы
🟢 Начальный уровень (Rust-basic)
Не прочитана
🔵 Средний уровень (Rust-middle)
41 Продвинутый Pattern Matching в Rust: деструктуризация, @-связывание и match guards (текущая)
Не прочитана

Связанные статьи