← Back to Rust Course | Chapter 11: Generics & Traits | Lesson 6 of 7

Display and Debug Traits

Display and Debug teach your type two different ways to turn itself into readable text: one polished for people, one detailed for developers.

Deriving Debug

#[derive(Debug)] automatically generates a Debug implementation, letting a struct be printed with {:?} for quick developer-facing inspection.

Example: Deriving Debug

markup
#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p = Point { x: 1, y: 2 };
    println!("{:?}", p);
}

Implementing Display Manually

Display has no automatic derive and must be implemented by hand, defining exactly how the type should look in clean, user-facing output via {}.

Example: Implementing Display Manually

markup
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: 4 };
    println!("{}", p);
}

Implementing Both Traits on the Same Type

A type can implement both Display and Debug at once, giving it two distinct textual representations depending on whether {} or {:?} is used.

Example: Implementing Both Traits on the Same Type

markup
use std::fmt;

#[derive(Debug)]
struct Money {
    cents: i64,
}

impl fmt::Display for Money {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "${:.2}", self.cents as f64 / 100.0)
    }
}

fn main() {
    let price = Money { cents: 1999 };
    println!("Display: {}", price);
    println!("Debug: {:?}", price);
}

Using write! Inside fmt

The write! macro is how both Display and Debug implementations produce their output, writing formatted text into the provided Formatter and returning a fmt::Result.

Example: Using write! Inside fmt

markup
use std::fmt;

struct Temperature(f64);

impl fmt::Display for Temperature {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:.1} degrees", self.0)
    }
}

fn main() {
    let t = Temperature(23.456);
    println!("{}", t);
}
Common Mistakes
  1. Trying to derive Display with #[derive(Display)] -- unlike Debug, Display has no built-in derive and must be implemented manually.
  2. Implementing Display but forgetting Debug is still needed separately for {:?} formatting to work.
  3. Returning a String directly from fmt instead of using write!(f, ...), which is the correct way to produce Display/Debug output.
Chapter Summary
  • Display ({}) must be implemented manually and is meant for clean, user-facing output.
  • Debug ({:?}) can be auto-derived with #[derive(Debug)] and is meant for developer-facing diagnostics.
  • Both traits are implemented by defining an fmt method that writes into a Formatter using the write! macro.
  • A type can implement both traits simultaneously, providing different output for {} versus {:?}.
🔒

Chapter Quiz — Complete all 7 topics to unlock

0/7 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.