Learn Rust Coding · Lekcja

Deref i ergonomia wrapperów

Sprawi Pan/Pani, że wrappery będą działać jak typy natywne.

Lekcja 4 z 413 kroki

Deref i ergonomia wrapperów to bezpłatna lekcja Learn Rust Coding na CoddyKit. To lekcja 4 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 z ergonomią

Opakowanie typu w newtype zwiększa bezpieczeństwo, ale zmniejsza wygodę: nagle wszędzie trzeba pisać wrapper.0.method() i ręcznie odtwarzać metody.

Trait Deref może przywrócić znaczną część tej wygody, pozwalając wrapperowi zachowywać się jak przechowywana w nim wartość.

Działanie Deref

Deref definiuje wynik wyrażenia *value i obsługuje operator .. Gdy wywołają Państwo metodę, której wrapper nie ma, kompilator ponownie próbuje znaleźć ją w obiekcie docelowym dereferencji.

Ten automatyczny krok nazywa się koercją dereferencji.

use std::ops::Deref;
struct MyBox<T>(T);
impl<T> Deref for MyBox<T> {
    type Target = T;
    fn deref(&self) -> &T { &self.0 }
}

Koercja dereferencji w działaniu

Po zaimplementowaniu Deref wywoływanie metod wartości wewnętrznej na wrapperze po prostu działa. Kompilator wstawia za Państwa .deref(), aż znajdzie metodę.

use std::ops::Deref;
struct Name(String);
impl Deref for Name {
    type Target = String;
    fn deref(&self) -> &String { &self.0 }
}
fn main() {
    let n = Name("rustacean".to_string());
    println!("len = {}", n.len()); // String::len via deref
}

DerefMut dla dostępu mutowalnego

Deref zapewnia tylko dostęp współdzielony. Aby za pośrednictwem wrappera wywoływać metody wymagające &mut self, należy również zaimplementować DerefMut, które zwraca mutowalną referencję do wartości wewnętrznej.

use std::ops::{Deref, DerefMut};
struct Stack(Vec<i32>);
impl Deref for Stack {
    type Target = Vec<i32>;
    fn deref(&self) -> &Vec<i32> { &self.0 }
}
impl DerefMut for Stack {
    fn deref_mut(&mut self) -> &mut Vec<i32> { &mut self.0 }
}

Koercja na granicach funkcji

Koercja dereferencji dotyczy również argumentów. &Name ulega koercji do &String, a ten typ z kolei do &str, dzięki czemu można bezpośrednio przekazać wrapper do funkcji oczekujących referencji do wartości wewnętrznej.

fn greet(who: &str) {
    println!("hi {}", who);
}
// greet(&name) works: &Name -> &String -> &str

Przykład koercji do uruchomienia

Ten program przekazuje referencję do wrappera tam, gdzie oczekiwany jest wycinek stringa. Łańcuch koercji dereferencji zachodzi niejawnie w miejscu wywołania.

use std::ops::Deref;
struct Tag(String);
impl Deref for Tag {
    type Target = String;
    fn deref(&self) -> &String { &self.0 }
}
fn shout(s: &str) { println!("{}!", s.to_uppercase()); }
fn main() {
    let t = Tag("ship".to_string());
    shout(&t);
}

Nie należy nadużywać Deref

Wytyczne dotyczące API Rust ostrzegają przed implementowaniem Deref dla typów, które nie są rzeczywistymi inteligentnymi wskaźnikami. Nadmierne używanie tego traitu sprawia, że dostępne metody wrappera stają się nieprzewidywalne i zaskakują czytelników.

Jeśli newtype ma ograniczać API, nieograniczone implementowanie Deref może ujawnić dokładnie te metody, które miały zostać ukryte.

AsRef jako ukierunkowana alternatywa

Gdy potrzebują Państwo jawnej konwersji zamiast automatycznej koercji, należy zaimplementować AsRef. Wywołujący jawnie pisze .as_ref(), dzięki czemu własna powierzchnia API wrappera pozostaje przejrzysta.

struct Path(String);
impl AsRef<str> for Path {
    fn as_ref(&self) -> &str { &self.0 }
}

Przekazywanie wybranych metod

W przypadku ograniczającego wrappera lepiej ręcznie zaimplementować tylko te metody, które chcą Państwo udostępnić. Zapewnia to pełną kontrolę nad API zamiast ujawniać wszystko za pośrednictwem Deref.

struct Counter(Vec<u8>);
impl Counter {
    fn len(&self) -> usize { self.0.len() }
    fn push(&mut self, b: u8) { self.0.push(b); }
}

Inteligentne wskaźniki używają Deref

Standardowe inteligentne wskaźniki, takie jak Box, Rc i Arc, implementują Deref. Dlatego można na nich przejrzyście wywoływać metody wartości wewnętrznej. Jest to prawidłowe i zamierzone zastosowanie tego traitu.

use std::rc::Rc;
fn main() {
    let shared = Rc::new(String::from("data"));
    // Deref lets us call String methods directly
    println!("len = {}", shared.len());
}

Wybór strategii ergonomii

Wyboru należy dokonać zgodnie z przeznaczeniem. Deref należy stosować dla rzeczywistych wrapperów będących inteligentnymi wskaźnikami, AsRef dla jawnych konwersji pożyczonych wartości, a ręczne przekazywanie metod wtedy, gdy newtype ma ograniczać API typu wewnętrznego.

Niewłaściwy wybór albo ukrywa zbyt wiele, albo ujawnia zbyt wiele.

Szybkie sprawdzenie

Proszę ustalić, dla którego wrappera warto zaimplementować Deref.

Podsumowanie

Deref i koercja dereferencji przywracają wrapperom wygodę użycia, pozwalając operatorowi . oraz argumentom będącym referencjami przejść do wartości wewnętrznej; DerefMut dodaje dostęp mutowalny.

Deref należy rezerwować dla rzeczywistych inteligentnych wskaźników. W przypadku ograniczających newtype należy używać AsRef do jawnych konwersji albo przekazywać tylko te metody, które chcą Państwo udostępnić.

Bezpłatny start

Ucz się Rust dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
39
Lekcje
144

Często zadawane pytania

Czy lekcja „Deref i ergonomia wrapperów” jest bezpłatna?

Tak — pełny tekst „Deref i ergonomia wrapperów” 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 „Deref i ergonomia wrapperów”?

Sprawi Pan/Pani, że wrappery będą działać jak typy natywne. Ć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 4 z 4.

Ile czasu zajmuje lekcja „Deref i ergonomia wrapperów”?

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. Wzorzec Builder
  2. Wzorzec Newtype
  3. Buildery ze stanem typu
  4. Deref i ergonomia wrapperów
← Powrót do Learn Rust Coding