Metody generyczne
Część sekcji Programowanie obiektowe ścieżki Rust w Coddy. Lekcja 25 z 61.
Struktura generyczna może przechowywać dowolny typ, ale nie jest zbyt użyteczna bez metod umożliwiających pracę z jej danymi. Aby zdefiniować metody dla struktury generycznej, potrzebujesz specjalnej składni w bloku impl.
Kluczem jest zadeklarowanie parametru generycznego w samym impl:
struct Wrapper<T> {
value: T,
}
impl<T> Wrapper<T> {
fn get(&self) -> &T {
&self.value
}
}
Zwróć uwagę na impl<T> przed Wrapper<T>. Informuje to Rust, że T jest parametrem typu generycznego dla całego bloku implementacji. Bez tej deklaracji Rust szukałby konkretnego typu o nazwie T i nie znalazłby go.
Metoda get zwraca &T: referencję do dowolnego typu przechowywanego przez opakowanie. Działa to niezależnie od tego, czy T jest liczbą całkowitą, ciągiem znaków czy dowolnym innym typem:
let num_wrapper = Wrapper { value: 100 };
let text_wrapper = Wrapper { value: "Rust" };
println!("{}", num_wrapper.get()); // 100
println!("{}", text_wrapper.get()); // Rust
Ta sama definicja metody działa w obu przypadkach, ponieważ typ generyczny T dostosowuje się do każdego konkretnego typu podczas kompilacji.
Wyzwanie
ŁatwyRozbuduj swój generyczny kontener o metody! Zbudujesz strukturę Box (nie mylić ze standardowym Box w Rust), która może przechowywać dowolny typ i udostępnia metody do pracy z jej zawartością.
Podzielisz swój kod na dwa pliki:
mybox.rs: Zdefiniuj publiczną generyczną strukturę o nazwieMyBox<T>z prywatnym polemcontentstypuT. Zaimplementuj metody dla tej struktury:- Funkcję skojarzoną
new, która tworzy nowy obiektMyBoxz podaną wartością - Metodę
peek, która zwraca referencję do zawartości (używając&self) - Metodę
replace, która przyjmuje nową wartość i zastępuje nią bieżącą zawartość (używając&mut self)
- Funkcję skojarzoną
main.rs: Dołącz swój moduł i pokaż działanie metod generycznych na różnych typach. Utworzysz obiekty typu box, sprawdzisz ich zawartość i zastąpisz wartości, aby pokazać działanie metod.
Pamiętaj o kluczowej składni implementowania metod dla generycznej struktury: przed MyBox<T> musisz umieścić impl<T>, aby poinformować Rust, że T jest parametrem generycznym dla całego bloku implementacji.
W swoim głównym pliku pokaż działanie MyBox przez:
- Utworzenie obiektu typu box z liczbą całkowitą (pierwsze wejście, sparsowane jako
i32) - Sprawdzenie jego zawartości i wypisanie wartości
- Zastąpienie zawartości nową liczbą całkowitą (drugie wejście, sparsowane jako
i32) - Ponowne sprawdzenie zawartości, aby pokazać zaktualizowaną wartość
- Utworzenie drugiego obiektu typu box z ciągiem znaków (trzecie wejście)
- Sprawdzenie zawartości obiektu typu box z ciągiem znaków
Wynik powinien mieć następujący format:
Integer box contains: {value}
After replace: {value}
String box contains: {value}Na przykład dla wejść 10, 25 i Rust:
Integer box contains: 10
After replace: 25
String box contains: RustOtrzymasz trzy wejścia: początkową liczbę całkowitą, liczbę całkowitą, która ją zastąpi, oraz wartość będącą ciągiem znaków.
Spróbuj swoich sił
mod mybox;
use mybox::MyBox;
fn main() {
// Odczytaj dane wejściowe
let mut input1 = String::new();
std::io::stdin().read_line(&mut input1).expect("Failed to read line");
let initial_int: i32 = input1.trim().parse().expect("Invalid integer");
let mut input2 = String::new();
std::io::stdin().read_line(&mut input2).expect("Failed to read line");
let replacement_int: i32 = input2.trim().parse().expect("Invalid integer");
let mut input3 = String::new();
std::io::stdin().read_line(&mut input3).expect("Failed to read line");
let string_value = input3.trim().to_string();
// TODO: Utwórz MyBox z początkową liczbą całkowitą
// TODO: Sprawdź jego zawartość i wypisz: "Integer box contains: {value}"
// TODO: Zastąp zawartość nową liczbą całkowitą
// TODO: Ponownie sprawdź zawartość i wypisz: "After replace: {value}"
// TODO: Utwórz drugi MyBox z wartością tekstową
// TODO: Sprawdź zawartość pudełka z tekstem i wypisz: "String box contains: {value}"
}
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