Rust Output Streams
A program has two output streams. Standard output carries the result.
Results out, talk aside
Send the result to stdout. Send the note to stderr. A file that captures stdout then holds only the answer:
println!("answer: 42");
eprintln!("note: computed in 3 ms");Lock stdout for a run of lines
println! locks and unlocks on every call. A locked handle keeps the hold for a whole run of lines.
let mut out = io::stdout().lock();
writeln!(out, "first")?;
writeln!(out, "second")?;writeln! hands you the error
println! panics when a write fails. writeln! returns a Result instead. The next lesson lives on that difference.
if let Err(e) = writeln!(out, "{line}") {
// the write failed, and e says why
}Flush before you wait
Output can sit in a buffer. flush() pushes it out. Flush before the program asks, waits, or sleeps.
print!("working...");
io::stdout().flush()?;Example
use std::io::{self, BufRead, Write};
fn main() -> io::Result<()> {
let stdin = io::stdin();
let mut out = io::stdout().lock();
let mut lines = 0;
for line in stdin.lock().lines() {
let line = line?;
lines += 1;
let words = line.split_whitespace().count();
writeln!(out, "{words}")?;
}
eprintln!("counted {lines} lines");
Ok(())
}Key points
- Results and data go to stdout.
- Errors, warnings, and progress notes go to stderr.
- A redirect captures stdout only.
- Stderr still reaches the screen.
- Lock stdout once for a run of writeln! calls.
- The lock also keeps two writers from interleaving lines.
- Flush stdout before a prompt.
- Buffered words may not have reached the screen yet.
- writeln! to a handle returns the error as a value.
In this example, the program reads two piped lines: "a b" and "c". It counts the words on each line. The counts 2 and 1 go to stdout through the locked handle. The note "counted 2 lines" goes to stderr through eprintln!. Send stdout to a file and the file holds only 2 and 1. The note still appears on the screen. That split is what lets the next tool in a pipe trust the data.
Note
println! and eprintln! panic on a failed write.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
A tool prints its progress notes with println! into a data pipe. What goes wrong?