Cechy z parametrami
Część sekcji Programowanie obiektowe ścieżki Rust w Coddy. Lekcja 33 z 61.
Jak dotąd nasze metody cechy przyjmowały tylko &self jako parametr. Metody cechy mogą jednak przyjmować dodatkowe parametry, tak jak zwykłe metody. Dzięki temu są znacznie bardziej przydatne w rzeczywistych zastosowaniach.
Definiując cechę, możesz uwzględnić dowolne parametry, których potrzebujesz w sygnaturach metod:
trait Calculator {
fn add(&self, a: i32, b: i32) -> i32;
fn multiply(&self, a: i32, b: i32) -> i32;
}
Ten trait Calculator wymaga dwóch metod, z których każda przyjmuje dwie liczby całkowite oprócz &self. Każdy typ implementujący ten trait musi udostępniać obie operacje z dokładnie takimi sygnaturami.
Oto, jak struktura może to zaimplementować:
struct BasicCalc;
impl Calculator for BasicCalc {
fn add(&self, a: i32, b: i32) -> i32 {
a + b
}
fn multiply(&self, a: i32, b: i32) -> i32 {
a * b
}
}
Teraz możesz używać tych metod z argumentami:
let calc = BasicCalc;
println!("{}", calc.add(5, 3)); // 8
println!("{}", calc.multiply(4, 7)); // 28
Cecha definiuje, jakie parametry przyjmuje każda metoda, a implementacja określa, jak te parametry są używane. Dzięki temu różne typy mogą wykonywać te same operacje na swój sposób: na przykład LoggingCalc może wypisywać każdą operację przed zwróceniem wyniku.
Wyzwanie
ŁatwyStwórzmy zestaw narzędzi do przetwarzania ciągów znaków, w którym różne procesory mogą przekształcać tekst na własne sposoby! Utworzysz cechę TextProcessor z metodami przyjmującymi parametry, a następnie zaimplementujesz ją dla dwóch różnych typów procesorów.
Rozmieścisz swój kod w trzech plikach:
processor.rs: Zdefiniuj publiczną cechęTextProcessorz dwiema metodami przyjmującymi parametry:repeat(&self, text: &str, times: u32) -> String: powtarza podany tekst określoną liczbę razytruncate(&self, text: &str, max_len: usize) -> String: skraca tekst do określonej maksymalnej długości
processors.rs: Utwórz dwie publiczne struktury implementujące twoją cechę:SimpleProcessor: jednostkowa struktura, która powtarza tekst, wstawiając spacje między powtórzeniami (np. "Hi" powtórzone 3 razy daje "Hi Hi Hi"), i skraca tekst przez proste obcięcie do maksymalnej długościFancyProcessor: jednostkowa struktura, która powtarza tekst, wstawiając " * " między powtórzeniami (np. "Hi" powtórzone 3 razy daje "Hi * Hi * Hi"), i skraca tekst, dodając "..." jeśli został on skrócony (tylko jeśli oryginalny tekst był dłuższy niż max_len)
main.rs: Połącz moduły i pokaż, jak te same metody cechy dają różne wyniki w zależności od użytego procesora.
W pliku głównym utwórz oba procesory i przetestuj je za pomocą danych wejściowych. Otrzymasz trzy dane wejściowe: ciąg tekstowy, liczbę powtórzeń i maksymalną długość.
Wyświetl cztery wiersze pokazujące działanie każdego procesora:
Simple repeat: {result}
Simple truncate: {result}
Fancy repeat: {result}
Fancy truncate: {result}Na przykład dla danych wejściowych Hello, 3 i 4:
Simple repeat: Hello Hello Hello
Simple truncate: Hell
Fancy repeat: Hello * Hello * Hello
Fancy truncate: Hell...Zwróć uwagę, że oba procesory spełniają ten sam kontrakt TextProcessor, ale każdy przekształca tekst na swój własny, unikalny sposób. Cecha określa, jakie parametry przyjmują metody, a każda implementacja decyduje, jak ich używać!
Otrzymasz trzy dane wejściowe: tekst do przetworzenia, liczbę powtórzeń (parsuj jako u32) oraz maksymalną długość tekstu po skróceniu (parsuj jako usize).
Spróbuj swoich sił
mod processor;
mod processors;
use processor::TextProcessor;
use processors::{SimpleProcessor, FancyProcessor};
fn main() {
// Wczytaj dane wejściowe
let mut text = String::new();
std::io::stdin().read_line(&mut text).expect("Failed to read line");
let text = text.trim();
let mut times_input = String::new();
std::io::stdin().read_line(&mut times_input).expect("Failed to read line");
let times: u32 = times_input.trim().parse().expect("Failed to parse times");
let mut max_len_input = String::new();
std::io::stdin().read_line(&mut max_len_input).expect("Failed to read line");
let max_len: usize = max_len_input.trim().parse().expect("Failed to parse max_len");
// Utwórz procesory
let simple = SimpleProcessor;
let fancy = FancyProcessor;
// TODO: Użyj procesorów do przekształcenia tekstu i wyświetl wyniki
// Wyświetl cztery wiersze:
// Simple repeat: {result}
// Simple truncate: {result}
// Fancy repeat: {result}
// Fancy truncate: {result}
}
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