SoFunction
Updated on 2025-03-04

Detailed explanation of the example of custom Debug debug output in Rust

In Rust, by implementing fmt::Debug for the type, you can customize the debug output of that type. fmt::Debug is a formatted trait in the standard library that is used to implement printing in the {:?} format. This trait is usually implemented by automatic derivation (#[derive(Debug)]), but you can also implement it manually for custom behavior.

Syntax and Examples

Automatic derivation (recommended method)

The easiest way is to use the #[derive(Debug)] macro:

#[derive(Debug)]
struct MyStruct {
    x: i32,
    y: i32,
}
fn main() {
    let instance = MyStruct { x: 10, y: 20 };
    println!("{:?}", instance);
}

Output:

MyStruct { x: 10, y: 20 }

Manually implement fmt::Debug

When you need to fully customize the output format, you can manually implement fmt::Debug for the type. This is often used to improve readability or to hide sensitive information.

Complete implementation example:

use std::fmt;
struct MyStruct {
    x: i32,
    y: i32,
}
impl fmt::Debug for MyStruct {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "MyStruct {{ x: {}, y: {} }}", , )
    }
}
fn main() {
    let instance = MyStruct { x: 10, y: 20 };
    println!("{:?}", instance);
}

Output:

MyStruct { x: 10, y: 20 }

Implementation steps of fmt::Debug

Implement fmt::Debug trait:
The fmt method needs to be implemented, which receives a Formatter parameter.

fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;

Use write! or f.debug_struct():
• Use write! to manually splice strings.
• It is more concise to use auxiliary methods such as f.debug_struct(). Custom debug output format

Use write! splicing format

use std::fmt;
struct Point {
    x: i32,
    y: i32,
}
impl fmt::Debug for Point {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Point({}, {})", , )
    }
}
fn main() {
    let p = Point { x: 3, y: 4 };
    println!("{:?}", p);
}

Output:

Point(3, 4)

Use f.debug_struct() to build output

f.debug_struct() is a more concise way to avoid manually splicing strings:

use std::fmt;
struct Point {
    x: i32,
    y: i32,
}
impl fmt::Debug for Point {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Point")
         .field("x", &)
         .field("y", &)
         .finish()
    }
}
fn main() {
    let p = Point { x: 3, y: 4 };
    println!("{:?}", p);
}

Output:

Point { x: 3, y: 4 }

Control the formatting of debug output

Formatter provides a variety of options to adjust the output format, such as whether to enable multi-line display.

Simple implementation of multi-line output

impl fmt::Debug for Point {
    fn fmt(&amp;self, f: &amp;mut fmt::Formatter&lt;'_&gt;) -&gt; fmt::Result {
        if () {
            // `{:#?}` format            write!(f, "Point {{\n    x: {},\n    y: {}\n}}", , )
        } else {
            // `{:?}` format            write!(f, "Point {{ x: {}, y: {} }}", , )
        }
    }
}
fn main() {
    let p = Point { x: 3, y: 4 };
    println!("{:?}", p);  // Single line    println!("{:#?}", p); // Multiple lines}

Output:

Point { x: 3, y: 4 }
Point {
x: 3,
y: 4
}

Application scenarios

• Sensitive information hiding:

For example, only partial fields are displayed, or the field content is blurred.

use std::fmt;
struct User {
    username: String,
    password: String,
}
impl fmt::Debug for User {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "User {{ username: {}, password: [REDACTED] }}", )
    }
}
fn main() {
    let user = User {
        username: "user123".to_string(),
        password: "secret".to_string(),
    };
    println!("{:?}", user);
}

Output:

User { username: user123, password: [REDACTED] }

• Simplify complex structures:
Provides a more friendly output format for complex data structures.

Things to note

1. The difference between fmt::Debug and fmt::Display:
• Debug is a debugging purpose and is suitable for the development stage.
• Display is a user-friendly format for display or logging.
2. Do not conflict with #[derive(Debug)]:

If you implement fmt::Debug manually, you do not need to derive #[derive(Debug)] again.
3. Follow the format convention:
If your type is part of the public API, it is recommended to output a standard format similar to {} or { field: value } for easy understanding.

Summarize

• fmt::Debug is a debug formatting tool in Rust for {:?} printing.
• It can be automatically generated through #[derive(Debug)] or can be implemented manually to meet custom needs.
• Using auxiliary methods such as f.debug_struct() can significantly simplify the implementation process, and it is recommended to use it first.

This is the article about custom Debug debug output in Rust. For more related contents of custom Debug debug output in Rust, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!