RustArena

Rust println! formatting: {}, {:?}, width and precision

A cheat sheet for Rust format strings: placeholders, inline {name} args, {:?}, {:.2}, padding and alignment, hex, binary and format!.

println!, print!, format!, eprintln! and write! all use the same format string syntax. Each {} is a placeholder filled by an argument.

Filling placeholders

fn main() {
    let item = "potion";
    let qty = 3;
    println!("{} x {}", qty, item);
    println!("{qty} x {item}");
    println!("{0} and {0} again, then {1}", item, qty);
    println!("{label}: {}", qty * 2, label = "doubled");
}
3 x potion
3 x potion
potion and potion again, then 3
doubled: 6

{qty} is an inline format argument: it captures the variable by name. It only accepts a plain name, not an expression, so {qty * 2} is an error; put expressions after the string.

The format spec cheat sheet

Everything after a : inside the braces controls how the value looks.

Spec Meaning Example Output
{} Display, the user-facing form {}, "hi" hi
{:?} Debug, the programmer form {:?}, "hi" "hi"
{:#?} pretty Debug, one field per line structs, vectors
{:.2} 2 digits after the decimal point 3.14159 3.14
{:8} minimum width 8 42 42
{:<8} {:^8} {:>8} left, center, right align "ab" ab
{:*^8} fill character *, centered "ab" ***ab***
{:05} pad with zeros 42 00042
{:+} always show the sign 42 +42
{:x} {:X} {:#x} hexadecimal 255 ff, FF, 0xff
{:b} {:#010b} binary, padded 5 101, 0b00000101
{:e} scientific notation 1500.0 1.5e3
{:width$} width from a variable width = 6

Numbers are right-aligned by default and text is left-aligned. Specs combine in a fixed order: fill and alignment, sign, #, 0, width, .precision, type. So {:>10.2} is "right-align in 10 columns with 2 decimals".

format!, eprintln! and write!

Common mistakes

Putting an expression inside the braces:

fn main() {
    let x = 5;
    println!("{x + 1}");
}
error: invalid format string: the `+` sign flag must appear after `:` in a format string

The message is misleading: rustc reads the + as a formatting flag (like the one in {:+}, which prints a + sign on positive numbers). The real fix is to move the calculation out of the braces: println!("{}", x + 1).

Printing your own struct with {} gives E0277, "Point doesn't implement std::fmt::Display". Add #[derive(Debug)] and use {:?}, or implement Display yourself.

A literal brace must be doubled: println!("{{}}") prints {}. A mismatch between placeholders and arguments (println!("{} {}", a)) is a compile error, not a runtime surprise.

Example

fn main() {
    let rows = [("Ferris", 1250.5, 7), ("Corro", 980.25, 12), ("Gopher", 15.0, 3)];
    println!("{:<8}|{:>10}|{:>5}", "name", "score", "games");
    println!("{:-<8}+{:->10}+{:->5}", "", "", "");
    for (name, score, games) in rows {
        println!("{name:<8}|{score:>10.2}|{games:>5}");
    }

    let id = 42;
    println!("ticket #{id:05}, hex {id:#x}, binary {id:#010b}");
    println!("change: {:+}, {:+}", 7, -3);

    let width = 12;
    println!("[{:^width$}]", "centered");

    let summary = format!("{} players", rows.len());
    println!("{summary:?}");
}

Output:

name    |     score|games
--------+----------+-----
Ferris  |   1250.50|    7
Corro   |    980.25|   12
Gopher  |     15.00|    3
ticket #00042, hex 0x2a, binary 0b00101010
change: +7, -3
[  centered  ]
"3 players"

Practice it