println!
The println! macro writes formatted text followed by a newline (\n) to the process's standard output stream (stdout).
Syntactic Forms
| Invocation Form | Example | Behavior |
|---|---|---|
| Empty (newline only) | println!(); |
Writes a single \n byte to stdout |
| Inline variable capture | println!("user = {name}, id = {id:?}"); |
Captures local bindings name (Display) and id (Debug) directly |
| Positional arguments | println!("{} + {} = {}", a, b, a + b); |
Substitutes arguments in order ({0}, {1}, {2}) |
| Named arguments | println!("{host}:{port}", host = "0.0.0.0", port = 80); |
Binds named placeholders explicitly in the call |
fn main() {
let service = "auth-api";
let port = 8080_u16;
let healthy = true;
println!("Starting {service} on port {port} (healthy={healthy})");
println!(); // Prints a blank line
println!("Hex port: {port:#06x}, Binary flags: {:04b}", 0b1010);
}
Starting auth-api on port 8080 (healthy=true)
Hex port: 0x1f90, Binary flags: 1010
Under the Hood: format_args! and Zero Intermediate String Allocation
Unlike calling println!("{}", format!(...)), invoking println!("x = {x}") does not allocate a heap String. Instead, println! expands to std::io::_print(format_args!("x = {x}\n")), which constructs a stack-allocated fmt::Arguments<'_> value and streams the formatted chunks directly into io::stdout()'s line-buffered writer.
Locking stdout for High-Throughput Loops (StdoutLock)
Each call to println! acquires and releases a mutex lock on the global io::stdout() handle and flushes on every newline (when attached to a terminal). When printing thousands of lines in a tight loop, lock stdout() once and wrap it in a BufWriter with writeln!:
use std::io::{self, BufWriter, Write};
fn main() -> io::Result<()> {
let stdout = io::stdout();
let mut handle = BufWriter::new(stdout.lock());
for i in 1..=3 {
writeln!(handle, "Batch line #{i}")?;
}
handle.flush()?;
Ok(())
}
Batch line #1
Batch line #2
Batch line #3
Panicking Behavior on Broken Pipe
If writing to stdout returns an I/O error, println! panics (or terminates on SIGPIPE). In CLI tools that pipe output into head/grep commands where broken pipes should be handled gracefully as io::Result<()>, use writeln!(io::stdout(), ...) instead of println!.