Menu
Coddy logo textTech

Сопоставление вариантов с данными

Часть раздела Object Oriented Programming путешествия по Rust на Coddy — урок 16 из 61.

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

Когда вы выполняете сопоставление с вариантом перечисления, содержащим данные, вы можете привязать эти данные к переменным прямо в шаблоне:

enum Event {
    Click { x: i32, y: i32 },
    KeyPress(char),
    Resize(u32, u32),
}

fn handle_event(event: Event) {
    match event {
        Event::Click { x, y } => {
            println!("Clicked at ({}, {})", x, y);
        }
        Event::KeyPress(key) => {
            println!("Key pressed: {}", key);
        }
        Event::Resize(width, height) => {
            println!("Resized to {}x{}", width, height);
        }
    }
}

Каждая ветвь извлекает данные по-разному в зависимости от структуры варианта. Для структурных вариантов вы используете { field_name } для извлечения именованных полей. Для кортежных вариантов вы используете позиционные переменные, такие как (width, height).

Имена переменных, которые вы выбираете, становятся доступными внутри этой ветки match. Это мощный инструмент, так как вы одновременно проверяете, какой вариант перед вами, и получаете доступ к его данным.

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

challenge icon

Задание

Легко

Давайте создадим обработчик команд, который обрабатывает различные типы пользовательских команд. Каждая команда несет в себе разные данные, и ваш обработчик будет использовать сопоставление с образцом (pattern matching) для извлечения этих данных и формирования соответствующих ответов.

Для организации кода вы создадите два файла:

  • command.rs: Определите публичное перечисление Command с тремя вариантами:
    • Say — содержит одно сообщение типа String (синтаксис кортежа)
    • Move — содержит именованные поля: direction (String) и steps (u32)
    • Calculate — содержит два значения i32, представляющих числа для сложения (синтаксис кортежа)
    Затем реализуйте метод execute, который использует match для деструктуризации каждого варианта и возвращает String с описанием выполненного действия.
  • main.rs: Подключите модуль команд, создайте по одному экземпляру каждого варианта команды, используя предоставленные входные данные, и вызовите метод execute для каждого из них, чтобы вывести результаты.

Ваш метод execute должен деструктурировать каждый вариант для доступа к его данным и возвращать сообщения строго в следующих форматах:

  • Для Say: Saying: {message}
  • Для Move: Moving {steps} steps {direction}
  • Для Calculate: {a} + {b} = {sum}

Ваш вывод должен отображать результат каждой команды на отдельной строке:

Saying: {message}
Moving {steps} steps {direction}
{a} + {b} = {sum}

Например, если сообщение для say — "Hello world", перемещение на 5 шагов "north", а вычисление для 10 и 25, вывод будет следующим:

Saying: Hello world
Moving 5 steps north
10 + 25 = 35

Вы получите пять входных значений: сообщение для say, направление, количество шагов и два числа для вычисления.

Шпаргалка

Сопоставление с образцом с помощью match позволяет деструктурировать варианты перечисления и извлекать их данные непосредственно в шаблоне.

Для кортежных вариантов используйте позиционные переменные:

enum Event {
    KeyPress(char),
    Resize(u32, u32),
}

match event {
    Event::KeyPress(key) => {
        println!("Key: {}", key);
    }
    Event::Resize(width, height) => {
        println!("{}x{}", width, height);
    }
}

Для структуроподобных вариантов используйте синтаксис именованных полей:

enum Event {
    Click { x: i32, y: i32 },
}

match event {
    Event::Click { x, y } => {
        println!("Clicked at ({}, {})", x, y);
    }
}

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

Попробуйте сами

mod command;

use command::Command;

fn main() {
    // Чтение входных данных
    let mut say_message = String::new();
    std::io::stdin().read_line(&mut say_message).expect("Failed to read line");
    let say_message = say_message.trim().to_string();

    let mut direction = String::new();
    std::io::stdin().read_line(&mut direction).expect("Failed to read line");
    let direction = direction.trim().to_string();

    let mut steps_input = String::new();
    std::io::stdin().read_line(&mut steps_input).expect("Failed to read line");
    let steps: u32 = steps_input.trim().parse().expect("Failed to parse steps");

    let mut num1_input = String::new();
    std::io::stdin().read_line(&mut num1_input).expect("Failed to read line");
    let num1: i32 = num1_input.trim().parse().expect("Failed to parse num1");

    let mut num2_input = String::new();
    std::io::stdin().read_line(&mut num2_input).expect("Failed to read line");
    let num2: i32 = num2_input.trim().parse().expect("Failed to parse num2");

    // TODO: Создать команду Say, используя say_message, и выполнить её
    
    // TODO: Создать команду Move, используя direction и steps, и выполнить её
    
    // TODO: Создать команду Calculate, используя num1 и num2, и выполнить её
    
    // TODO: Вывести результаты выполнения каждой команды
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Object Oriented Programming