0Pricing
Learn Rust Coding · Lekcja

Obiekty cech i dyn

Dynamiczne wywołanie

Obiekty cech i dyn to bezpłatna lekcja Learn Rust Coding na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Learn Rust Coding, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Learn Rust Coding zawiera 4 lekcji w sumie.

Problem: różne typy

Generyki z ograniczeniami traitów świetnie działają, gdy każde wywołanie używa jednego konkretnego typu. Co jednak, jeśli chce Pan/Pani utworzyć kolekcję różnych typów, które współdzielą trait? Generyki nie mogą przechowywać takiej mieszanki.

Rozwiązaniem są obiekty traitów.

Czym jest obiekt traitu?

Obiekt traitu to wartość, do której odwołuje się za pomocą wskaźnika i słowa kluczowego dyn, na przykład &dyn Trait lub Box<dyn Trait>.

Pozwala traktować wiele konkretnych typów jednolicie w czasie działania programu.

Box z dyn Trait

Box<dyn Trait> posiada na stercie wartość pewnego typu implementującego trait. Można wywoływać metody traitu bez znajomości konkretnego typu.

trait Speak { fn say(&self) -> String; }
struct Dog;
impl Speak for Dog { fn say(&self) -> String { String::from("Woof") } }

fn main() {
    let animal: Box<dyn Speak> = Box::new(Dog);
    println!("{}", animal.say());
}

Vec obiektów traitów

Największa korzyść: pojedynczy wektor może przechowywać wiele różnych typów, o ile każdy z nich implementuje dany trait.

trait Speak { fn say(&self) -> String; }
struct Dog;
struct Cat;
impl Speak for Dog { fn say(&self) -> String { String::from("Woof") } }
impl Speak for Cat { fn say(&self) -> String { String::from("Meow") } }

fn main() {
    let zoo: Vec<Box<dyn Speak>> = vec![Box::new(Dog), Box::new(Cat)];
    for animal in &zoo {
        println!("{}", animal.say());
    }
}

Dynamiczne wywoływanie

W przypadku obiektów traitów metoda, którą należy wywołać, jest wybierana w czasie działania przez wyszukanie jej w ukrytej tabeli (vtable). Nazywa się to dynamicznym wywołaniem.

Kosztem jest niewielkie pośrednie odwołanie, a korzyścią — elastyczność w czasie działania.

Funkcje zwracające obiekty traitów

Funkcja może zwracać Box<dyn Trait>, gdy konkretny typ może się zmieniać. Jest to przydatne w funkcjach fabrykujących, które wybierają typ w czasie działania.

trait Speak { fn say(&self) -> String; }
struct Dog;
struct Cat;
impl Speak for Dog { fn say(&self) -> String { String::from("Woof") } }
impl Speak for Cat { fn say(&self) -> String { String::from("Meow") } }

fn make(kind: &str) -> Box<dyn Speak> {
    if kind == "dog" { Box::new(Dog) } else { Box::new(Cat) }
}

fn main() {
    println!("{}", make("cat").say());
}

Pożyczone obiekty traitów

Można też przekazać pożyczony obiekt traitu za pomocą &dyn Trait, gdy nie jest potrzebne przejęcie własności. Nie wiąże się to z alokacją na stercie.

trait Speak { fn say(&self) -> String; }
struct Dog;
impl Speak for Dog { fn say(&self) -> String { String::from("Woof") } }

fn announce(s: &dyn Speak) {
    println!("heard: {}", s.say());
}

fn main() {
    let d = Dog;
    announce(&d);
}

Bezpieczeństwo obiektowe

Nie każdy trait może być obiektem traitu. Trait musi być bezpieczny obiektowo: w przybliżeniu jego metody nie mogą zwracać Self przez wartość ani używać parametrów typów generycznych.

Metody przyjmujące &self i używające konkretnych typów są dozwolone.

Przykład niebezpieczny obiektowo

Trait z metodą zwracającą Self nie może być używany jako dyn, ponieważ rozmiar typu Self za wskaźnikiem jest nieznany. Traity używane jako obiekty traitów powinny być proste.

Przykład w stylu systemu wtyczek

Obiekty traitów świetnie sprawdzają się w systemach wtyczek: można przechowywać listę programów obsługi za dyn i uruchamiać je wszystkie bez przejmowania się konkretnymi typami.

trait Task { fn run(&self) -> i32; }
struct Add { a: i32, b: i32 }
struct Negate { x: i32 }
impl Task for Add { fn run(&self) -> i32 { self.a + self.b } }
impl Task for Negate { fn run(&self) -> i32 { -self.x } }

fn main() {
    let tasks: Vec<Box<dyn Task>> = vec![Box::new(Add { a: 2, b: 3 }), Box::new(Negate { x: 7 })];
    let total: i32 = tasks.iter().map(|t| t.run()).sum();
    println!("total {}", total);
}

Kiedy użyć dyn

Używaj obiektów traitów, gdy potrzebujesz heterogenicznych kolekcji, typów wybieranych w czasie działania albo chcesz ograniczyć rozrost kodu wynikający z wielu instancjacji generycznych.

W przeciwnym razie preferuj typy generyczne, aby uzyskać maksymalną wydajność.

Szybki sprawdzian

Sprawdź, jak dobrze rozumiesz obiekty traitów.

Podsumowanie

Omówiono dynamiczne wywołanie:

  • Obiekty traitów używają dyn za wskaźnikiem (Box<dyn T>, &dyn T)
  • Umożliwiają tworzenie heterogenicznych kolekcji i używanie typów wybieranych w czasie działania
  • Wywołania metod przechodzą przez vtable (dynamiczne wywołanie)
  • Traity muszą być bezpieczne obiektowo, aby można było używać ich w ten sposób

Często zadawane pytania

Czy lekcja „Obiekty cech i dyn” jest bezpłatna?

Tak — pełny tekst „Obiekty cech i dyn” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Learn Rust Coding, przejdź na CoddyKit PRO. Kurs Learn Rust Coding zawiera 4 lekcji w sumie.

Co nauczysz się w „Obiekty cech i dyn”?

Dynamiczne wywołanie Ćwiczysz Learn Rust Coding z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Learn Rust Coding?

Nie wymagamy żadnego doświadczenia. Learn Rust Coding w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „Obiekty cech i dyn”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Learn Rust Coding?

Tak. Każda lekcja Learn Rust Coding zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Definiowanie cech
  2. Obiekty cech i dyn
  3. Wywołanie statyczne a dynamiczne
  4. Metody domyślne
← Powrót do Learn Rust Coding