Common Standard Macros

format!

The format! macro formats values according to a compile-time-checked format string and returns the result as a newly heap-allocated String.

How format! Expands (format_args! + fmt::format)

When you invoke format!("id={id}, status={status:?}"), the macro expands to:

std::fmt::format(format_args!("id={id}, status={status:?}"))
  1. format_args! validates the format string at compile time, checks that each interpolated variable implements the required formatting trait (Display, Debug, LowerHex, etc.), and builds a zero-allocation std::fmt::Arguments<'_> value on the stack.
  2. std::fmt::format allocates a String and writes the formatted fragments into it. (If the format string is a plain literal with no {} placeholders, format!("literal") is optimized directly to "literal".to_owned().)
#[derive(Debug)]
struct Version(u8, u8, u8);

fn main() {
    let pkg = "tokio";
    let ver = Version(1, 40, 0);

    // Combines Display (`{pkg}`), Debug (`{ver:?}`), and hex formatting (`{:04x}`):
    let summary = format!("package={pkg} version={ver:?} flags={:#06x}", 0x00A5);
    println!("{summary}");
}
package=tokio version=Version(1, 40, 0) flags=0x00a5

Formatting Traits and Their Specifiers in format!

Specifier Required Trait in std::fmt Example (n = 42)
{} Display "42"
{:?} / {:#?} Debug "42"
{:x} / {:X} LowerHex / UpperHex "2a" / "2A"
{:b} Binary "101010"
{:o} Octal "52"
{:e} / {:E} LowerExp / UpperExp "4.2e1" / "4.2E1"
{:p} Pointer "0x16b9a74c0"

When to Avoid format!

  • Printing directly to stdout / stderr / a file: Use println!, eprintln!, or write!(writer, ...) directly instead of println!("{}", format!(...)) so no intermediate String is allocated.
  • Appending to an existing String: Use use std::fmt::Write; write!(&mut buf, ...) instead of buf.push_str(&format!(...)).
  • Single value to String: Prefer val.to_string() over format!("{val}") for a single unformatted Display value.