Rust Display Trait
Display is the trait that gives a type a tidy, user-facing text form. The {} placeholder prints a value through Display.
The {} placeholder asks for Display
Once a type has Display, {} prints it in its tidy, user-facing form:
let price = Money { dollars: 12, cents: 5 };
println!("{price}");Write the impl by hand
Display is never derived — you write the one fmt method yourself:
impl fmt::Display for Money {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "${}.{:02}", self.dollars, self.cents)
}
}Several pieces: stop at the first error
End each earlier write! with ? — if one write fails, the method stops and returns that error at once:
write!(f, "[")?;
write!(f, "{}", self.name)?;
write!(f, "]")Let the caller's width work
A row of plain write! calls ignores a caller's {:>7} — the value prints unpadded, as [#new]. Build the text first, then hand it to f.pad, and the width, fill and alignment all apply:
impl fmt::Display for Tag {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let text = format!("#{}", self.0);
f.pad(&text)
}
}
// println!("[{:>7}]", tag) with Tag("new"):Display hands you to_string
You never write ToString yourself — Display brings it along, building the same tidy text as a String:
let text: String = price.to_string();
println!("{text}");Example
use std::fmt;
struct Money { dollars: u32, cents: u32 }
impl fmt::Display for Money {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "${}.{:02}", self.dollars, self.cents)
}
}
fn main() {
let price = Money { dollars: 12, cents: 5 };
println!("price = {}", price);
println!("as text = {}", price.to_string());
}Key points
- Display is never derived: you write impl fmt::Display for YourType by hand, because Rust cannot guess the right look
- The last write! in fmt is the return value, because fmt must hand back a fmt::Result that says whether writing worked
- Vec<T> and other generic containers have no Display at all: print them with {:?}, or wrap them in your own type and give the wrapper a Display
- The formatter reports what was asked: f.width(), f.precision(), f.alternate() and f.sign_plus() let one impl answer {:.2}, {:#} and {:+} differently instead of ignoring them
- Debug is the programmer-facing form, printed with {:?}.
- A price can print as $12.05 through Display.
- Display gives a type the text form its users see.
In this example, Money holds dollars and cents as two separate numbers. The Display impl writes a dollar sign, the dollars, and a dot. It writes the cents padded to two digits with {:02}. So 5 cents shows as 05, not 5. main can now print price with {}, giving $12.05. The second line calls .to_string(), which Display provides for free, and it builds exactly the same text.
Note
Writing Display gives you ToString for free: every Display type gains .to_string(), which builds the same tidy text as a String.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
You write a Display impl for one of your types. Which extra power does the type get for free?