Deref în Rust

Trait-ul din spatele operatorului * și al conversiei automate &Box<T> -> &T, &String -> &str (deref coercion).

Sintaxă
impl Deref for Tip {
    type Target = Alt;
    fn deref(&self) -> &Alt { ... }
}

Ce face Deref

Deref spune ce se obține când „urmezi” o valoare ca pe un pointer: *x. Îl implementează pointerii inteligenți (Box, Rc, Arc), dar și String (spre str) și Vec<T> (spre [T]).

Efectul cel mai util este deref coercion: când o funcție cere &str și îi dai &String, Rust aplică automat deref. La fel, metodele lui str se pot apela pe un String, iar metodele lui T pe un Box<T>. Pentru acces mutabil există perechea DerefMut.

Implementează Deref pentru tipuri „înveliș” (newtype, pointeri proprii), nu ca să imiți moștenirea din alte limbaje: codul devine greu de urmărit.

Parametri

Parametru Descriere
type Target Tipul spre care „arată” valoarea.
deref(&amp;self) Returnează referința spre Target.

Ce returnează

&Self::Target.

Exemple

Exemplul 1: Un newtype care se folosește ca &str

use std::ops::Deref;

struct NumeOras(String);

impl Deref for NumeOras {
    type Target = str;
    fn deref(&self) -> &str {
        &self.0
    }
}

fn salut(oras: &str) {
    println!("Bun venit în {oras}!");
}

fn main() {
    let o = NumeOras(String::from("Suceava"));
    salut(&o);                                   // &NumeOras -> &str automat
    println!("{} litere, majuscule: {}", o.chars().count(), o.to_uppercase());
    println!("începe cu S: {}", o.starts_with('S'));
}

Rezultat

Bun venit în Suceava!
7 litere, majuscule: SUCEAVA
începe cu S: true

Exemplul 2: Operatorul * și Box

fn main() {
    let x = 5;
    let r = &x;
    let b = Box::new(10);
    println!("{} {}", *r + 1, *b + 1);

    let text: Box<String> = Box::new(String::from("Galați"));
    let felie: &str = &text;                     // Box<String> -> String -> str
    println!("{felie} are {} octeți", text.len());
}

Rezultat

6 11
Galați are 7 octeți

Greșeli frecvente

  • Folosești Deref ca să „moștenești” metodele unui tip în altul (Caine → Animal). Rust recomandă compoziția și trait-urile pentru asta.
  • Uiți că deref returnează o referință, nu o valoare: let s: String = *text; pe un &String încearcă să mute valoarea și nu compilează.

Comenzi înrudite

  • AsRef: Conversie ieftină de la referință la referință; folosit în funcții generice care acceptă String, &str, PathBuf etc.
  • Drop: Codul rulat automat când o valoare iese din domeniu (destructor): închidere de fișiere, eliberare de resurse, mesaje.
  • String::as_str: Returnează un &str care împrumută tot conținutul String-ului; util la match și unde se cere explicit &str.
  • Sized: Trait marker pentru tipurile cu dimensiune cunoscută la compilare; ?Sized permite și str, [T], dyn Trait.