fmt::Formatter în Rust

Obiectul primit de fmt() în Display și Debug: destinația textului plus opțiunile din {:...} (lățime, precizie, #).

Sintaxă
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    f.write_str("text")?;
    write!(f, "{}", self.camp)
}

Ce face fmt::Formatter

Când implementezi Display sau Debug, metoda fmt primește un &mut Formatter. În el scrii textul: cu write!(f, ...) pentru text formatat sau cu f.write_str("...") pentru un text fix (puțin mai rapid, fără formatare).

Formatter-ul știe și ce a cerut apelantul în acolade: f.width() pentru {:10}, f.precision() pentru {:.2}, f.alternate() pentru {:#}, f.align(), f.fill(). write_str ignoră lățimea și alinierea; ca să le respecți, folosește f.pad(text).

Pentru Debug, Formatter-ul are ajutoare care produc formatul standard: debug_struct, debug_tuple, debug_list, debug_map.

Parametri

Parametru Descriere
write_str(s) Scrie textul fix s, fără formatare.
width() / precision() Option<usize>: lățimea și precizia cerute în acolade.
alternate() true pentru forma {:#}.
pad(s) Scrie s respectând lățimea, alinierea și precizia (trunchiere).

Ce returnează

Metodele de scriere returnează fmt::Result, care se propagă cu ?.

Exemple

Exemplul 1: write_str, write! și forma alternativă

use std::fmt;

struct Pret {
    bani: u64,
}

impl fmt::Display for Pret {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{},{:02}", self.bani / 100, self.bani % 100)?;
        if f.alternate() {
            f.write_str(" lei (TVA inclus)")
        } else {
            f.write_str(" lei")
        }
    }
}

fn main() {
    let p = Pret { bani: 123450 };
    println!("{p}");
    println!("{p:#}");
}

Rezultat

1234,50 lei
1234,50 lei (TVA inclus)

Exemplul 2: Lățime și aliniere cu pad

Cu write_str, {:>10} ar fi ignorat. pad aplică lățimea, alinierea și precizia cerute.

use std::fmt;

struct Oras(&'static str);

impl fmt::Display for Oras {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad(self.0)
    }
}

struct OrasFaraPad(&'static str);

impl fmt::Display for OrasFaraPad {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.0)
    }
}

fn main() {
    println!("[{:>10}]", Oras("Iași"));
    println!("[{:^10}]", Oras("Cluj"));
    println!("[{:-<10}]", Oras("Arad"));
    println!("[{:.3}]", Oras("Timișoara"));
    println!("[{:>10}]", OrasFaraPad("Iași"));
}

Rezultat

[      Iași]
[   Cluj   ]
[Arad------]
[Tim]
[Iași]

Greșeli frecvente

  • Folosești println! în interiorul lui fmt. Textul trebuie scris în f (write!(f, ...)), nu pe ecran.
  • Te miri că {:>10} nu are efect pe tipul tău. write!(f, ...) și write_str nu aplică lățimea cerută; folosește f.pad sau citește f.width().

Comenzi înrudite

  • fmt::Display: Trait-ul pentru afișarea către utilizator cu {}; se implementează manual și aduce automat to_string().
  • fmt::Debug: Trait-ul pentru afișarea de depanare cu {:?} și {:#?}; se obține aproape mereu cu #[derive(Debug)].
  • fmt::Formatter::debug_struct: Ajută la scrierea manuală a lui Debug în formatul standard Nume { camp: valoare }, inclusiv forma {:#?}.
  • fmt::Write: Trait-ul care permite scrierea de text formatat cu write!/writeln! direct într-un String sau alt destinatar de text.