dbg! în Rust

Afișează rapid, pentru depanare, fișierul, linia, expresia și valoarea ei (în format Debug) pe stderr, apoi returnează valoarea.

Sintaxă
dbg!(expresie)                // afișează și returnează valoarea
let x = dbg!(a * 2) + 1;
dbg!(a, b, c);                // mai multe valori deodată
dbg!();                       // doar fișierul și linia

Ce face dbg!

dbg!(expresie) scrie pe ieșirea de eroare [fisier:linie:coloana] expresie = valoare, cu valoarea afișată ca {:#?}, și apoi returnează valoarea. De aceea îl poți pune în mijlocul unei expresii fără să schimbi ce face codul: let total = dbg!(pret * cantitate) + transport;.

Primește valoarea prin mutare și o dă înapoi. Pentru a nu muta o valoare pe care o folosești și după, scrie dbg!(&valoare). Cu mai multe argumente, dbg!(a, b) le afișează pe fiecare și returnează un tuplu.

Este făcut pentru depanare temporară: Clippy are o regulă (dbg_macro) care îl găsește în cod, ca să nu-l uiți înainte de commit. În modul release funcționează la fel (nu dispare). Pentru mesaje permanente folosește eprintln! sau un crate de jurnalizare. (Exemplele de pe această pagină sunt rulate cu rustc main.rs, de aceea fișierul apare ca main.rs; într-un proiect Cargo apare src/main.rs.)

Ce returnează

Valoarea expresiei primite (sau un tuplu, pentru mai multe argumente).

Exemple

Exemplul 1: Urmărirea unui calcul

Fiecare dbg! arată expresia și valoarea ei, dar programul calculează exact ca fără ele. &cos evită mutarea vectorului. Rândurile cu [main.rs:...] sunt pe stderr, iar cel cu „Total” pe stdout.

fn main() {
    let cos = vec![("pâine", 2, 5.5), ("lapte", 1, 9.0)];
    let subtotal: f64 = cos.iter().map(|&(_, n, p)| n as f64 * p).sum();
    let transport = if dbg!(subtotal) < 50.0 { 15.0 } else { 0.0 };
    let total = dbg!(subtotal + transport);
    dbg!(&cos);
    println!("Total: {total} lei");
}

Rezultat (dbg! scrie pe ieșirea de eroare)

[main.rs:4:24] subtotal = 20.0
[main.rs:5:17] subtotal + transport = 35.0
[main.rs:6:5] &cos = [
    (
        "pâine",
        2,
        5.5,
    ),
    (
        "lapte",
        1,
        9.0,
    ),
]
Total: 35 lei

Exemplul 2: Într-o funcție recursivă

dbg! în jurul apelului recursiv arată fiecare rezultat intermediar, de la cel mai adânc apel spre primul.

fn factorial(n: u64) -> u64 {
    if n <= 1 {
        return 1;
    }
    n * dbg!(factorial(n - 1))
}

fn main() {
    let rezultat = factorial(4);
    println!("4! = {rezultat}");
}

Rezultat (dbg! scrie pe ieșirea de eroare)

[main.rs:5:9] factorial(n - 1) = 1
[main.rs:5:9] factorial(n - 1) = 2
[main.rs:5:9] factorial(n - 1) = 6
4! = 24

Greșeli frecvente

  • Scrii dbg!(valoare) și apoi folosești valoare: dacă nu este Copy, a fost mutată. Folosește dbg!(&valoare) sau păstrează rezultatul: let valoare = dbg!(valoare);.
  • Cauți ieșirea lui dbg! în fișierul în care ai redirecționat stdout. dbg! scrie pe stderr.
  • Lași dbg! în codul final. Rulează cargo clippy -- -W clippy::dbg_macro ca să le găsești.

Comenzi înrudite

  • eprintln! și eprint!: Ca println! și print!, dar scriu pe ieșirea de eroare (stderr), separată de rezultatul normal al programului.
  • println! și print!: Afișează text pe ieșirea standard: println! adaugă la final un rând nou, print! nu. Acoladele {} sunt înlocuite cu valori.
  • assert_eq! și assert_ne!: Verifică dacă două valori sunt egale (assert_eq!) sau diferite (assert_ne!); la eșec, panica afișează ambele valori.
  • line!, file! și column!: Dau poziția din codul sursă unde sunt scrise: numărul liniei, coloana și numele fișierului. Utile în mesaje de jurnal și erori.