fmt::Display în Rust

Trait-ul pentru afișarea către utilizator cu {}; se implementează manual și aduce automat to_string().

Sintaxă
impl fmt::Display for Tip {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "...", ...)
    }
}

Ce face fmt::Display

Display definește cum arată valoarea ta în println!("{}", x), format! și to_string(). Nu se poate deriva: Rust nu poate ghici forma „frumoasă” pentru un tip, așa că o scrii tu, în metoda fmt, cu write!(f, ...).

Orice tip cu Display primește automat to_string() (prin ToString). Tipurile de erori implementează și ele Display, pentru mesajul de eroare. write!(f, ...) nu aplică singur lățimea și alinierea cerute ({:>10}); pentru ele folosește f.pad.

Ce returnează

Metoda fmt returnează fmt::Result (de obicei rezultatul lui write!).

Exemple

Exemplul 1: Un produs afișat în română

use std::fmt;

struct Produs {
    nume: String,
    pret_bani: u64,
    stoc: u32,
}

impl fmt::Display for Produs {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let lei = self.pret_bani / 100;
        let bani = self.pret_bani % 100;
        write!(f, "{} – {lei},{bani:02} lei", self.nume)?;
        match self.stoc {
            0 => write!(f, " (stoc epuizat)"),
            1 => write!(f, " (ultimul produs)"),
            n => write!(f, " ({n} bucăți în stoc)"),
        }
    }
}

fn main() {
    let produse = [
        Produs { nume: "Cozonac cu nucă".into(), pret_bani: 3450, stoc: 12 },
        Produs { nume: "Zacuscă de casă".into(), pret_bani: 1599, stoc: 1 },
        Produs { nume: "Telemea de oaie".into(), pret_bani: 2800, stoc: 0 },
    ];
    for p in &produse {
        println!("{p}");
    }
    let text: String = produse[0].to_string();   // to_string vine din Display
    println!("{} caractere", text.chars().count());
}

Rezultat

Cozonac cu nucă – 34,50 lei (12 bucăți în stoc)
Zacuscă de casă – 15,99 lei (ultimul produs)
Telemea de oaie – 28,00 lei (stoc epuizat)
47 caractere

Exemplul 2: Display pentru un enum

use std::fmt;

#[derive(Clone, Copy)]
enum Anotimp {
    Primavara,
    Vara,
    Toamna,
    Iarna,
}

impl fmt::Display for Anotimp {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let nume = match self {
            Anotimp::Primavara => "primăvară",
            Anotimp::Vara => "vară",
            Anotimp::Toamna => "toamnă",
            Anotimp::Iarna => "iarnă",
        };
        f.pad(nume)   // respectă lățimea și alinierea cerute
    }
}

fn main() {
    for a in [Anotimp::Primavara, Anotimp::Vara, Anotimp::Toamna, Anotimp::Iarna] {
        println!("[{a:>10}] Acum este {a}.");
    }
}

Rezultat

[ primăvară] Acum este primăvară.
[      vară] Acum este vară.
[    toamnă] Acum este toamnă.
[     iarnă] Acum este iarnă.

Greșeli frecvente

  • Încerci #[derive(Display)]: nu există în std. Display se implementează manual.
  • Implementezi ToString direct. Implementează Display, iar to_string() vine automat.
  • Folosești println! în fmt în loc de write!(f, ...).

Comenzi înrudite

  • fmt::Debug: Trait-ul pentru afișarea de depanare cu {:?} și {:#?}; se obține aproape mereu cu #[derive(Debug)].
  • fmt::Formatter: Obiectul primit de fmt() în Display și Debug: destinația textului plus opțiunile din {:…} (lățime, precizie, #).
  • ToString: Trait-ul metodei to_string(); există automat pentru orice tip cu Display, deci nu se implementează direct.
  • fmt::Write: Trait-ul care permite scrierea de text formatat cu write!/writeln! direct într-un String sau alt destinatar de text.