Course contentsShow
← Rust
Lesson 542 of 1,9105. Type System and TraitsFree lesson

Display and Debug Trait Customization

Control the string representation of custom types for better observability and logging.

In this lesson, you will learn how to take control of how your custom types appear in logs and terminal output by manually implementing the std::fmt::Debug and std::fmt::Display traits.

Why Customize Representation?

By default, Rust allows you to use the #[derive(Debug)] attribute to print structs and enums. However, once your data structures become complex, the default "struct-style" output might be too verbose or hide the information most relevant to your debugging process. Similarly, Display allows you to define a user-facing, clean version of your data that isn't intended for developers, but for end-users.

Implementing Debug and Display

The Debug trait is intended for developers ({:?}), while Display is intended for clean, readable output ({}).

Here is how you manually implement them:

use std::fmt;

struct User {
    id: u32,
    username: String,
}

// Custom Debug: Optimized for developer inspection
impl fmt::Debug for User {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "User(id: {}, name: '{}')", self.id, self.username)
    }
}

// Custom Display: Optimized for end-user readability
impl fmt::Display for User {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} (ID: {})", self.username, self.id)
    }
}

The fmt Method

Both traits require you to implement the fmt method. The f: &mut fmt::Formatter acts as a buffer. The write! macro is your primary tool here; it functions exactly like println!, but instead of writing to the standard output, it writes directly into the formatter provided by the trait.

  • Debug ({:?}): Use this to show internal state, even if it is technical or messy. It is your diagnostic tool.
  • Display ({}): Use this to present data elegantly. If you don't implement Display, your type cannot be used with the {} placeholder in format strings.

By controlling these implementations, you turn opaque data structures into clear, observable signals during runtime, making your code significantly easier to maintain and troubleshoot.

Key Takeaway: Implement Debug for developer diagnostics and Display for user-facing output to ensure your data is always presented exactly how you need it.