Klauzula where
Część sekcji Programowanie obiektowe ścieżki Rust w Coddy. Lekcja 42 z 61.
W miarę dodawania kolejnych ograniczeń cech sygnatury funkcji mogą stawać się trudne do odczytania. Rozważ funkcję z wieloma parametrami generycznymi, z których każdy wymaga kilku cech:
fn complex_operation<T: Display + Clone, U: Debug + Summary>(first: T, second: U) {
// ...
}
To działa, ale sygnatura staje się coraz bardziej złożona. Klauzula where oferuje czytelniejszą alternatywę, przenosząc ograniczenia cech za listę parametrów:
fn complex_operation<T, U>(first: T, second: U)
where
T: Display + Clone,
U: Debug + Summary,
{
// ...
}
Obie wersje są funkcjonalnie identyczne: klauzula where służy wyłącznie czytelności. Wymagania dotyczące każdego typu znajdują się w osobnym wierszu, dzięki czemu łatwo sprawdzić, czego potrzebuje każdy parametr generyczny.
Klauzula where staje się szczególnie przydatna, gdy ograniczenia są złożone lub gdy masz wiele parametrów generycznych. Dzięki niej nazwa funkcji i parametry są od razu widoczne, a ograniczenia są wymienione osobno poniżej. To preferowany styl w większości baz kodu Rust, gdy ograniczenia wykraczają poza proste T: Trait.
Wyzwanie
ŁatwyStwórzmy system przetwarzania danych, który używa klauzuli where, aby zachować czytelność złożonych ograniczeń cech! Utworzysz funkcję generyczną z wieloma parametrami typów, z których każdy wymaga innych cech, i uporządkujesz ograniczenia za pomocą składni where.
Rozmieścisz kod w dwóch plikach:
processor.rs: Zdefiniuj dwie publiczne cechy i funkcję generyczną, która używa ich obu:Summarize: cecha z metodąsummary, która przyjmuje&selfi zwracaStringValidate: cecha z metodąvalidate, która przyjmuje&selfi zwracabool
process_items, która przyjmuje dwa parametry różnych typów generycznych. Użyj klauzuliwhere, aby określić, że pierwszy typ musi implementować zarównoClone, jak iSummarize, a drugi typ musi implementowaćValidate. Funkcja powinna wypisać podsumowanie pierwszego elementu, a następnie informację, czy drugi element jest prawidłowy.main.rs: Utwórz dwie publiczne struktury implementujące wymagane cechy:Article: z publicznym polemtitle(String). ZaimplementujSummarize, aby zwracałaArticle: {title}, i wyprowadź cechęClone.Form: z publicznym polemfilled(bool). ZaimplementujValidate, aby zwracała wartośćfilled.
process_items, przekazując oba elementy.
Klauzula where sprawia, że sygnatura funkcji jest znacznie czytelniejsza niż upychanie wszystkich ograniczeń w nawiasach ostrych. Wymagania każdego typu są zapisane w osobnym wierszu, dzięki czemu łatwo zobaczyć, czego potrzebuje każdy parametr generyczny.
Wynik powinien wyświetlać podsumowanie, a następnie rezultat walidacji:
Article: {title}
Valid: {true/false}Na przykład dla danych wejściowych Rust Tips i true:
Article: Rust Tips
Valid: trueA dla danych wejściowych Breaking News i false:
Article: Breaking News
Valid: falseOtrzymasz dwa dane wejściowe: tytuł artykułu oraz informację, czy formularz jest wypełniony (parsuj jako bool).
Spróbuj swoich sił
mod processor;
use processor::{Summarize, Validate, process_items};
use std::io;
// TODO: Zdefiniuj publiczną strukturę Article z publicznym polem title (String)
// Wyprowadź Clone dla Article
// TODO: Zaimplementuj Summarize dla Article
// Metoda summary powinna zwracać "Article: {title}"
// TODO: Zdefiniuj publiczną strukturę Form z publicznym polem filled (bool)
// TODO: Zaimplementuj Validate dla Form
// Metoda validate powinna zwracać wartość filled
fn main() {
let mut title = String::new();
io::stdin().read_line(&mut title).expect("Failed to read line");
let title = title.trim().to_string();
let mut filled_input = String::new();
io::stdin().read_line(&mut filled_input).expect("Failed to read line");
let filled: bool = filled_input.trim().parse().expect("Failed to parse bool");
// TODO: Utwórz Article z podanym title
// TODO: Utwórz Form z podaną wartością filled
// TODO: Wywołaj process_items z article i form
}
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