Сопоставление вариантов с данными
Часть раздела 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. Это мощный инструмент, так как вы одновременно проверяете, какой вариант перед вами, и получаете доступ к его данным.
Компилятор гарантирует, что вы обработаете каждый вариант, а извлеченные значения готовы к использованию немедленно — никаких дополнительных шагов не требуется.
Задание
ЛегкоДавайте создадим обработчик команд, который обрабатывает различные типы пользовательских команд. Каждая команда несет в себе разные данные, и ваш обработчик будет использовать сопоставление с образцом (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: Вывести результаты выполнения каждой команды
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Object Oriented Programming
1Методы и поведение
Введение в блоки реализацииПараметр SelfИзменяемые методыАссоциированные функцииНесколько блоков реализацииЦепочки вызовов методовИтоги: действия с Rectangle4Проект: Виртуальный питомец
Определение питомцаКормление питомца2Инкапсуляция и модули
Основы модулейКлючевое слово PublicПриватные поляГеттерыСеттерыИтоги — Безопасный сейф5Обобщения
Обобщённые структурыОбобщённые методыНесколько обобщённых типовОбобщённые функцииПовторение — Координатная точка8Трейты как ограничения
Синтаксис ограничений трейтовМножественные ограниченияКонструкция whereВозврат типов с трейтамиИтоги — Обобщённый принтер11Паттерны проектирования в Rust
Паттерн NewtypeКомпозицияТрейт DropFrom и IntoИтоги — Мок-объект Smart Pointer3Продвинутые перечисления
Перечисления с даннымиМетоды в перечисленияхСопоставление вариантов с даннымиСнова об Option EnumИтоги — перечисление Shape6Определение трейтов
Что такое трейт?Реализация трейтовРеализации по умолчаниюПереопределение реализаций по умолчаниюТрейты с параметрамиИтоги — Media Player