Skip to content

Output macros and destinations

All macros in the formatting family share the same format-string language. The useful distinction is where the formatted bytes go and whether a newline is appended.

Macro Destination Newline Return
format! new String no String
print! / println! stdout no / yes ()
eprint! / eprintln! stderr no / yes ()
write! / writeln! fmt::Write or io::Write no / yes fmt::Result or io::Result
format_args! deferred formatting arguments no fmt::Arguments

Use stdout for a program’s primary output. Use stderr for errors and progress that should remain separate from piped data.

EXAMPLE: CI-CHECKEDCOMPILED · examples/format-output/src/reference_examples.rs#output-streams
println!("result={}", 42);
eprintln!("warning: retrying");

print! does not append a newline. Because stdout is frequently line-buffered, call flush() when text must be visible immediately.

EXAMPLE: CI-CHECKEDCOMPILED · examples/format-output/src/reference_examples.rs#output-flush
use std::io::{self, Write};

print!("Continue? [y/N] ");
io::stdout().flush().unwrap();

The standard documentation notes that print! locks stdout on every call. For a hot loop, lock once and write through the handle.

EXAMPLE: CI-CHECKEDCOMPILED · examples/format-output/src/reference_examples.rs#output-lock
use std::io::{self, Write};

let stdout = io::stdout();
let mut output = stdout.lock();
for value in 0..3 {
    writeln!(output, "{value}").unwrap();
}

write! targets either std::fmt::Write for Unicode strings or std::io::Write for byte-oriented output.

EXAMPLE: CI-CHECKEDTEST ASSERTED · examples/format-output/src/reference_examples.rs#output-string
use std::fmt::Write;

let mut output = String::new();
write!(&mut output, "{:#06x}", 42).unwrap();
assert_eq!(output, "0x002a");