Implementacje domyślne
Część sekcji Programowanie obiektowe ścieżki Rust w Coddy. Lekcja 31 z 61.
Jak dotąd każda zdefiniowana przez nas metoda cechy była tylko sygnaturą: wymaganiem bez treści. Ale co, jeśli większość typów implementujących cechę używałaby tej samej logiki? Rust pozwala podać implementację domyślną bezpośrednio w definicji cechy.
Zamiast kończyć sygnaturę metody średnikiem, dodajesz ciało:
trait Greet {
fn greet(&self) -> String {
String::from("Hello there!")
}
}
Teraz każdy typ implementujący Greet automatycznie otrzymuje tę metodę, bez konieczności pisania kodu w bloku impl:
struct Guest;
impl Greet for Guest {}
let visitor = Guest;
println!("{}", visitor.greet()); // Cześć!
Puste impl Greet for Guest {} jest poprawne, ponieważ trait już udostępnia to zachowanie. Struktura po prostu „deklaruje zgodność” z traitem i otrzymuje domyślną metodę za darmo.
Ten wzorzec jest przydatny, gdy chcesz zdefiniować współdzielone zachowanie, które sprawdza się w większości przypadków. Typy, które potrzebują czegoś innego, mogą nadpisać zachowanie domyślne (czego nauczysz się w następnej lekcji), a typy, którym odpowiada standardowe zachowanie, nie muszą go powtarzać.
Wyzwanie
ŁatwyPoznajmy możliwości domyślnych implementacji, budując system powiadomień! Utworzysz trait, który od razu zapewnia standardowe zachowanie, dzięki czemu typy mogą z niego skorzystać bez pisania powtarzalnego kodu.
Podzielisz swój kod na trzy pliki:
notifiable.rs: Zdefiniuj publiczny traitNotifiablez metodąnotify(&self) -> String, która ma domyślną implementację. Powinna ona zwracać"You have a new notification!". Każdy typ implementujący ten trait automatycznie otrzyma to zachowanie, bez konieczności wpisywania czegokolwiek w bloku impl.alerts.rs: Utwórz dwie proste publiczne struktury jednostkowe, które implementują Twój trait:EmailAlert: implementujeNotifiablez pustym blokiem impl (korzysta z domyślnej implementacji)SystemAlert: również implementujeNotifiablez pustym blokiem impl (korzysta z domyślnej implementacji)
main.rs: Połącz moduły i pokaż, że oba typy alertów korzystają z tego samego domyślnego zachowania. Utwórz instancje obu struktur i wywołaj ich metodynotify.
W pliku głównym utwórz EmailAlert i SystemAlert, a następnie wypisz ich powiadomienia w osobnych wierszach.
Oczekiwany wynik:
You have a new notification!
You have a new notification!Zauważ, że oba typy generują identyczny wynik: na tym polega zaleta domyślnych implementacji! Żadna ze struktur nie musiała zawierać kodu metody notify, a mimo to obie mają w pełni funkcjonalne zachowanie związane z powiadomieniami. W następnej lekcji dowiesz się, jak nadpisywać te wartości domyślne, gdy typ wymaga własnego zachowania.
Spróbuj swoich sił
mod notifiable;
mod alerts;
use notifiable::Notifiable;
use alerts::{EmailAlert, SystemAlert};
fn main() {
// TODO: Utwórz instancję EmailAlert
// TODO: Utwórz instancję SystemAlert
// TODO: Wyświetl powiadomienie z EmailAlert
// TODO: Wyświetl powiadomienie z SystemAlert
}
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