🎓 A1Learner
🔍
0 of 149 lessons completed

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?