← 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.
Syntax
rust
use std::fmt;

impl fmt::Display for Name {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.field)
    }
}

#[derive(Debug)]

Deriving Debug

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

Example: Deriving Debug

markup
// Auto-generate #[derive(Debug)] for the type below
#[derive(Debug)]
// Define a struct `Point` to group related fields together
struct Point {
    x: i32,
    y: i32,
}

// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `p`, set to `Point { x: 1, y: 2 }`
    let p = Point { x: 1, y: 2 };
    // Print "{:?}" to the console, substituting in `p` (with a trailing newline)
    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
// Bring `std::fmt` into scope
use std::fmt;

// Define a struct `Point` to group related fields together
struct Point {
    x: i32,
    y: i32,
}

// Implement methods on `fmt`
impl fmt::Display for Point {
    // Define the function `fmt` taking `&self`, `f` and returning a `fmt::Result`
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `p`, set to `Point { x: 3, y: 4 }`
    let p = Point { x: 3, y: 4 };
    // Print "{}" to the console, substituting in `p` (with a trailing newline)
    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
// Bring `std::fmt` into scope
use std::fmt;

// Auto-generate #[derive(Debug)] for the type below
#[derive(Debug)]
// Define a struct `Money` to group related fields together
struct Money {
    cents: i64,
}

// Implement methods on `fmt`
impl fmt::Display for Money {
    // Define the function `fmt` taking `&self`, `f` and returning a `fmt::Result`
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "${:.2}", self.cents as f64 / 100.0)
    }
}

// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `price`, set to `Money { cents: 1999 }`
    let price = Money { cents: 1999 };
    // Print "Display: {}" to the console, substituting in `price` (with a trailing newline)
    println!("Display: {}", price);
    // Print "Debug: {:?}" to the console, substituting in `price` (with a trailing newline)
    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
// Bring `std::fmt` into scope
use std::fmt;

// Define a struct `Temperature` to group related fields together
struct Temperature(f64);

// Implement methods on `fmt`
impl fmt::Display for Temperature {
    // Define the function `fmt` taking `&self`, `f` and returning a `fmt::Result`
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:.1} degrees", self.0)
    }
}

// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `t`, set to `Temperature(23.456)`
    let t = Temperature(23.456);
    // Print "{}" to the console, substituting in `t` (with a trailing newline)
    println!("{}", t);
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
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.