Essential Standard Traits
Display
The std::fmt::Display trait formats a value for user-facing text output using the {} format specifier and cannot be automatically derived with #[derive(Display)].
Trait Definition
pub trait Display {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
}
Unlike Debug, which targets developers and has a canonical structure for any type, Display defines how a value appears to end users in logs, CLI output, or error messages. Because user-facing representation is a design decision, Display must always be implemented manually.
Implementing Display
Implement fmt using the write! macro to write formatted text into the Formatter buffer f:
use std::fmt;
struct ByteSize(u64);
impl fmt::Display for ByteSize {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
const KB: u64 = 1024;
const MB: u64 = 1024 * KB;
if self.0 >= MB {
write!(f, "{:.2} MiB", self.0 as f64 / MB as f64)
} else if self.0 >= KB {
write!(f, "{:.2} KiB", self.0 as f64 / KB as f64)
} else {
write!(f, "{} B", self.0)
}
}
}
fn main() {
println!("{}", ByteSize(512));
println!("{}", ByteSize(4096));
println!("{}", ByteSize(5_242_880));
}
512 B
4.00 KiB
5.00 MiB
Automatic ToString Blanket Implementation
The standard library provides a blanket implementation of ToString for every type that implements Display:
impl<T: fmt::Display + ?Sized> ToString for T {
// Provides .to_string()
}
Once a type implements Display, calling .to_string() on it works automatically without a separate impl ToString:
use std::fmt;
struct Coordinate {
lat: f64,
lon: f64,
}
impl fmt::Display for Coordinate {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({:.4}, {:.4})", self.lat, self.lon)
}
}
fn main() {
let loc = Coordinate {
lat: 23.6238,
lon: 90.5000,
};
let s: String = loc.to_string();
println!("Formatted string: {s}");
}
Formatted string: (23.6238, 90.5000)
Display vs. Debug
| Aspect | Display ({}) |
Debug ({:?}) |
|---|---|---|
| Intended audience | End users, CLI output, error messages | Developers, logs, test assertions |
Derivable via #[derive] |
No — must be written manually | Yes (#[derive(Debug)]) |
Blanket ToString impl |
Yes — provides .to_string() |
No |
Standard containers (Vec<T>, Option<T>) |
Do not implement Display |
Implement Debug when T: Debug |
Rules for Display::fmt
- Never panic inside
fmt. If formatting fails, propagate thefmt::Errorreturned bywrite!using?. - Do not allocate an intermediate
Stringviaformat!only to pass it tof.write_str(...); write directly tofwithwrite!(f, ...).