mirror of
https://github.com/leonardomso/rust-skills.git
synced 2026-09-14 19:33:21 +08:00
5f0b2079f8
Add unsafe, concurrency, conversions, and pattern-matching categories plus rules across existing ones, and correct advice that was outdated for Rust 1.96.
2.7 KiB
2.7 KiB
type-display-vs-debug
Use
Displayfor user-facing output andDebugfor diagnostics; never swap them
Why It Matters
Debug ({:?}) is for developers: logs, panic messages, test assertions, and dbg!(). It should always be derived and reflects internal structure. Display ({}) is for end users: CLI output, error messages surfaced to humans, and log fields meant to be read in production. std::error::Error requires Display so that error chains read naturally. Routing Debug output to users leaks implementation details; routing Display output to log frameworks loses structural information.
Bad
#[derive(Debug)]
struct ParseError {
input: String,
line: u32,
}
// Mistake 1: using Debug output in a user-facing message
fn report_error(e: &ParseError) {
eprintln!("failed: {:?}", e); // leaks internal field names
}
// Mistake 2: implementing Display by calling debug
use std::fmt;
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self) // wrong — duplicates Debug
}
}
Good
use std::fmt;
#[derive(Debug)] // derive Debug for free diagnostic output
struct ParseError {
input: String,
line: u32,
}
// Hand-write Display for a clean, human-readable message
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "parse error on line {}: {:?}", self.line, self.input)
}
}
impl std::error::Error for ParseError {}
fn main() {
let e = ParseError { input: "foo bar".into(), line: 42 };
// User-facing: clean sentence
eprintln!("error: {e}");
// Developer/log: structured dump
eprintln!("debug: {e:?}");
}
Guidelines
| Trait | Format | Audience | How to implement |
|---|---|---|---|
Debug |
{:?} / {:#?} |
Developers, logs | #[derive(Debug)] (almost always) |
Display |
{} |
End users, error messages | Hand-write to describe the condition clearly |
- Never derive
Display— it must be intentionally written. #[derive(Debug)]on every public type (API Guidelines C-DEBUG).- If your error type implements
std::error::Error, itsDisplayoutput becomes the human-readable error message that propagates throughanyhow::Contextand similar. - The
{:#?}pretty-print form is stillDebug; use it in tests for readable assertion output, not in user-facing code.
See Also
- api-common-traits - implement
Debug,Clone,PartialEqeagerly - err-thiserror-lib -
thiserrorgenerates correctDisplayfrom#[error("...")] - type-numeric-fmt - hex/octal/binary formatting for numeric newtypes