dbg!
The dbg! macro prints the source file, line number, column number, verbatim expression text, and Debug ({:#?}) value of one or more expressions to standard error (stderr), and then returns ownership of the evaluated value so it can be wrapped around any sub-expression in place.
How dbg!(expr) Works
let y = dbg!(x * 2) + 1;
│
├── 1. Evaluates `x * 2` ONCE into a temporary `tmp`
├── 2. Prints `[src/main.rs:4:13] x * 2 = 20` to `stderr`
└── 3. Returns `tmp` (20) by value so `20 + 1` evaluates to `21`
| Invocation Form | Return Type | What It Prints to stderr |
|---|---|---|
dbg!() |
() |
[file:line:col] (execution trace marker) |
dbg!(expr) |
Same type T as expr |
[file:line:col] expr = {val:#?} |
dbg!(a, b, c) |
Tuple (A, B, C) |
Prints each expression on its own line and returns (a, b, c) |
Inspecting Sub-Expressions and Recursive Calls Without Restructuring Code
Because dbg!(expr) evaluates expr once and returns its value, you can wrap an intermediate calculation, condition, or recursive argument without introducing temporary let variables:
fn factorial(n: u32) -> u32 {
if dbg!(n <= 1) {
dbg!(1)
} else {
dbg!(n * factorial(n - 1))
}
}
fn main() {
let result = factorial(3);
println!("Final result on stdout: {result}");
}
[src/main.rs:2:8] n <= 1 = false
[src/main.rs:2:8] n <= 1 = false
[src/main.rs:2:8] n <= 1 = true
[src/main.rs:3:9] 1 = 1
[src/main.rs:5:9] n * factorial(n - 1) = 2
[src/main.rs:5:9] n * factorial(n - 1) = 6
Final result on stdout: 6
Ownership Note: dbg!(&val) vs. dbg!(val)
Because dbg!(val) takes val by value and returns it (match val { tmp => { eprintln!(...); tmp } }), writing dbg!(my_string); as a standalone statement drops the returned String at the semicolon and moves my_string!
If you want to inspect a non-Copy variable without moving ownership out of it, either assign the result back (let s = dbg!(s);) or pass a shared reference (dbg!(&s);):
fn main() {
let name = String::from("BorrowMe");
// Passing `&name` borrows `name` and returns `&String`, leaving `name` valid:
dbg!(&name);
println!("Still owned in main: {name}");
}
[src/main.rs:5:5] &name = "BorrowMe"
Still owned in main: BorrowMe