Dopasowywanie wariantów danych
Część sekcji Programowanie obiektowe ścieżki Rust w Coddy. Lekcja 16 z 61.
W poprzedniej lekcji używasz match wewnątrz metod enum, aby obsługiwać różne warianty. Teraz skupimy się na tym, jak match faktycznie wyodrębnia dane przechowywane wewnątrz tych wariantów: technice zwanej destrukturyzacją.
Gdy dopasowujesz wariant wyliczenia, który przechowuje dane, możesz przypisać te dane do zmiennych bezpośrednio we wzorcu:
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);
}
}
}
Każda gałąź wyodrębnia dane inaczej, zależnie od struktury wariantu. W przypadku wariantów podobnych do struktur używasz { field_name }, aby wyodrębnić nazwane pola. W przypadku wariantów krotkowych używasz zmiennych pozycyjnych, takich jak (width, height).
Wybrane przez ciebie nazwy zmiennych stają się dostępne wewnątrz tej gałęzi dopasowania. To potężne rozwiązanie, ponieważ jednocześnie sprawdzasz, który wariant masz, i uzyskujesz dostęp do jego danych.
Kompilator gwarantuje, że obsłużysz każdy wariant, a wyodrębnione wartości są od razu gotowe do użycia: nie potrzeba żadnych dodatkowych kroków.
Wyzwanie
ŁatwyZbudujmy procesor poleceń, który obsługuje różne typy poleceń użytkownika. Każde polecenie zawiera inne dane, a procesor będzie używać dopasowania wzorców, aby wyodrębnić te dane i wygenerować odpowiednie odpowiedzi.
Utworzysz dwa pliki, aby uporządkować swój kod:
command.rs: Zdefiniuj publiczny typ wyliczeniowyCommandz trzema wariantami:Say: przechowuje pojedynczą wiadomość typuString(składnia krotkowa)Move: przechowuje nazwane pola:direction(String) isteps(u32)Calculate: przechowuje dwie wartościi32reprezentujące liczby do dodania (składnia krotkowa)
execute, która używamatch, aby rozpakować każdy wariant i zwrócić wartośćStringopisującą wykonaną czynność.main.rs: Zaimportuj moduł poleceń, utwórz po jednej instancji każdego wariantu polecenia, korzystając z podanych danych wejściowych, i wywołaj metodęexecutedla każdej z nich, aby wypisać wyniki.
Metoda execute powinna rozpakowywać każdy wariant, aby uzyskać dostęp do jego danych, i zwracać komunikaty w dokładnie następujących formatach:
- Dla
Say:Saying: {message} - Dla
Move:Moving {steps} steps {direction} - Dla
Calculate:{a} + {b} = {sum}
Wynik powinien wyświetlać rezultat każdego polecenia w osobnym wierszu:
Saying: {message}
Moving {steps} steps {direction}
{a} + {b} = {sum}Na przykład dla wiadomości polecenia Say "Hello world", polecenia Move z 5 krokami w kierunku "north" oraz obliczenia z użyciem 10 i 25, wynik wyglądałby tak:
Saying: Hello world
Moving 5 steps north
10 + 25 = 35Otrzymasz pięć danych wejściowych: wiadomość polecenia Say, kierunek, liczbę kroków oraz dwie liczby do obliczenia.
Spróbuj swoich sił
mod command;
use command::Command;
fn main() {
// Odczytaj dane wejściowe
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: Utwórz polecenie Say, używając say_message, i je wykonaj
// TODO: Utwórz polecenie Move, używając direction i steps, i je wykonaj
// TODO: Utwórz polecenie Calculate, używając num1 i num2, i je wykonaj
// TODO: Wypisz wyniki wykonania każdego polecenia
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Metody i zachowanie
Wprowadzenie do bloków implementacjiParametr selfMetody modyfikująceFunkcje powiązaneWiele bloków implementacjiŁańcuchowe wywoływanie metodPowtórzenie — działania na prostokącie4Projekt: Wirtualne zwierzątko
Definiowanie zwierzątkaKarmienie zwierzątka7Standardowe cechy
Cecha DebugCecha DisplayClone i CopyCechy równościPowtórka – punkt do wydrukowania10Projekt: System dokumentów
Trait DrawKomponent tekstowy2Hermetyzacja i moduły
Podstawy modułówSłowo kluczowe publicPola prywatneGetterySetteryPodsumowanie — bezpieczna skrytka5Typy generyczne
Struktury generyczneMetody generyczneWiele typów generycznychFunkcje generycznePodsumowanie – punkt współrzędnych8Cechy jako ograniczenia
Składnia ograniczeń cechWiele ograniczeńKlauzula whereZwracanie typów z użyciem cechPodsumowanie — generyczna drukarka11Wzorce projektowe w Rust
Wzorzec NewtypeKompozycjaTrait DropFrom i IntoPodsumowanie — atrapowy inteligentny wskaźnik3Zaawansowane typy wyliczeniowe
Typy wyliczeniowe z danymiMetody typów wyliczeniowychDopasowywanie wariantów danychTyp wyliczeniowy Option — powtórzeniePodsumowanie — typ wyliczeniowy Shape6Definiowanie cech
Czym jest cecha?Implementowanie cechImplementacje domyślneNadpisywanie wartości domyślnychCechy z parametramiPowtórzenie — odtwarzacz multimedialnyPoćwicz samodzielnie: Kompilator Rust online