Nugget 2
Home
You write println!("{}", my_struct) and the compiler shouts at you.
Meet Debug and Display — the two traits that let your
types be printed, formatted, and logged.
struct Point { x: i32, y: i32 }
fn main() {
let p = Point { x: 3, y: 7 };
println!("{}", p); // ❌ doesn't implement `Display`
println!("{:?}", p); // ❌ doesn't implement `Debug`
}
Rust won't let you print a struct until you tell it how. This is your
first encounter with traits — Debug and Display are
standard library traits that control formatting.
Debug
The fastest way to make a type printable is #[derive(Debug)].
Add it above your struct and use {:?}:
#[derive(Debug)]
struct Point { x: i32, y: i32 }
fn main() {
let p = Point { x: 3, y: 7 };
println!("{:?}", p); // ✅ Point { x: 3, y: 7 }
println!("{:#?}", p); // ✅ Pretty-printed:
// Point {
// x: 3,
// y: 7,
// }
}
💡 {:#?} vs {:?}
{:#?} pretty-prints with indentation — great for complex nested
structures. {:?} is compact, single-line output.
Display
Debug is auto-generated and often ugly. When you want {}
to show something human-readable, implement Display yourself:
use std::fmt;
struct Point { x: i32, y: i32 }
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
fn main() {
let p = Point { x: 3, y: 7 };
println!("{}", p); // ✅ (3, 7)
// {:?} still doesn't work — no Debug
}
⚠️ Display cannot be derived
Rust has no way to know what "human-readable" means for your type — you must
write Display by hand. Debug is the only printable
trait you can auto-derive.
Most Rust code derives Debug for developer tooling and implements
Display for users:
use std::fmt;
#[derive(Debug)] // auto-generates {:?}
struct Point { x: i32, y: i32 }
impl fmt::Display for Point { // hand-written for {}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
fn main() {
let p = Point { x: 3, y: 7 };
println!("{}", p); // ✅ (3, 7) — human friendly
println!("{:?}", p); // ✅ Point { x: 3, y: 7 } — dev friendly
dbg!(&p); // ✅ dbg!() needs Debug too
}
.to_string()
Any type that implements Display automatically gets a
.to_string() method via a blanket implementation in the standard
library:
let p = Point { x: 3, y: 7 };
let s: String = p.to_string(); // ✅ works because of Display
assert_eq!(s, "(3, 7)");
You didn't write to_string() — Rust provided it because
Display is implemented. That's the power of traits.
#[derive(Debug)] is the quickest way to make a struct printable for debugging.Display is for user-facing output — you write it by hand.{:?} for Debug, {} for Display, {:#?} for pretty-printed.dbg!() requires Debug — great for quick logging.Display gives you .to_string() for free.