🎓 A1Learner
🔍

Rust Debugging with dbg!

dbg! is a macro that prints a value to the error output and hands the value back. Its reports name the file and the line, so each report can be traced.

One line, the whole story

dbg! wraps a sum. It prints the file, the line, the code, and the answer. It also hands the answer back, so total still gets its 5. The line below arrives on the error output:

fn main() {
    let total = dbg!(2 + 3);
    println!("total = {total}");
}

Peek without taking

dbg! takes the value it prints. Lend it instead, with &. The report uses the pretty Debug form, one field per line:

#[derive(Debug)]
struct Rectangle { width: u32, height: u32 }
fn main() {
    let rect = Rectangle { width: 60, height: 50 };
    let rect = dbg!(&rect);
    println!("still mine: {} x {}", rect.width, rect.height);
}

dbg! in the middle of a line

dbg! can sit inside a longer line. Here it reports the whole Vec. Then len() runs on the same Vec:

fn main() {
    let n = dbg!(vec![1, 2, 3]).len();
    println!("n = {n}");
}

A bare dbg! marks the spot

With nothing inside, dbg! prints just the file and the line. Use it as a flag. The flag proves the program reached this line:

fn main() {
    dbg!();
    println!("halfway");
}

The two outputs stay apart

Run the first program again and split the streams. Send the error output away and only the real output stays. Send the normal output away and only the dbg! report stays:

// in your terminal:
// $ cargo run 2> /dev/null
total = 5
// $ cargo run 1> /dev/null
[src/main.rs:2:17] 2 + 3 = 5

Example

fn average(scores: &[i32]) -> i32 {
    let total: i32 = scores.iter().sum();
    dbg!(total);
    total / scores.len() as i32
}

fn main() {
    let scores = [70, 85, 90];
    let avg = average(&scores);
    println!("average = {avg}");
}

Key points

  • dbg! prints to the error output, called stderr.
  • dbg! never prints to the normal output, called stdout.
  • A program can pipe its real output onward.
  • The dbg! lines stay on the screen.
  • dbg! returns the value it printed.
  • dbg! can sit inside a line and change nothing else on that line.
  • dbg! prints the file name and the line and column numbers.
  • Ten dbg! lines never blur into one.
  • Use dbg!(&value) to peek at a value the program still owns.
  • The & lends the value for the print.
  • Nothing moves.

In this example, average adds the scores and divides by the count. The dbg! line sits between the sum and the division. On the error output it prints [src/main.rs:3:5] total = 245. That one line proves the sum is right, so the bug hunt can skip the loop. The normal output prints average = 81. Nothing about the maths changed. dbg! only watched.

Note

dbg! stays live in release builds.

dbg! is a normal macro, not a debug-only check.

Every dbg! must be hunted down before the program ships.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Rust Playground

Exercise

You left one dbg! in a program and built the release version. What happens?