Standard Input and Output

stdin()

std::io::stdin() constructs and returns a std::io::Stdin handle to the current process's standard input stream. Because Stdin is a zero-sized handle (0 bytes!) that references a static process-wide buffer protected by a Mutex, calling io::stdin() multiple times is free and always accesses the same shared stream.

Methods Directly on std::io::Stdin

Method Signature Description
io::stdin() pub const fn stdin() -> Stdin Returns a handle to the shared standard input stream
.lock(&self) pub fn lock(&self) -> StdinLock<'static> Locks the global Stdin mutex and returns a BufRead-implementing guard with 'static lifetime!
.read_line(&self, buf) pub fn read_line(&self, buf: &mut String) -> Result<usize> Locks Stdin, appends one line (including \n or \r\n) to buf, and returns the byte count read (0 on EOF)
.lines(self) pub fn lines(self) -> Lines<StdinLock<'static>> Consumes Stdin, locks it, and returns an iterator yielding io::Result<String> lines (with \n / \r\n stripped!)
.split(self, byte) pub fn split(self, byte: u8) -> Split<StdinLock<'static>> Returns an iterator splitting input on byte (such as b'\0' for xargs -0)

Note: Since Rust 1.62, io::stdin().lock() returns StdinLock<'static> directly—so you no longer need to bind let stdin = io::stdin(); in a separate variable before calling stdin.lock()!

Comparing stdin().read_line(&mut buf) and stdin().lines()

`stdin().read_line(&mut buf)`:
  - Appends to your existing `buf: String` (reuses heap capacity if you call `buf.clear()`!)
  - KEEPS trailing `\n` or `\r\n` (use `buf.trim_end()` to strip)
  - Returns `Ok(0)` at End-of-File (EOF)

`stdin().lines()`:
  - Allocates a fresh `String` per line
  - STRIPS trailing `\n` and `\r\n` automatically
  - Ends iteration (`None`) at EOF
use std::io::{self, BufRead, Cursor};

fn parse_key_values(input: impl BufRead) -> io::Result<Vec<(String, String)>> {
    let mut pairs = Vec::new();
    // `.lines()` strips `\n` / `\r\n` automatically on any `BufRead` (including `stdin().lock()`):
    for line_res in input.lines() {
        let line = line_res?;
        if let Some((k, v)) = line.split_once('=') {
            pairs.push((k.trim().to_string(), v.trim().to_string()));
        }
    }
    Ok(pairs)
}

fn main() -> io::Result<()> {
    // Verify `io::stdin()` handle size and `StdinLock<'static>` acquisition:
    let _stdin_lock: io::StdinLock<'static> = io::stdin().lock();
    drop(_stdin_lock);

    let mock_stdin = Cursor::new("host = 127.0.0.1\nport = 8080\r\n");
    let parsed = parse_key_values(mock_stdin)?;
    println!("size of io::Stdin: {} bytes", size_of::<io::Stdin>());
    println!("parsed pairs:      {:?}", parsed);
    Ok(())
}
size of io::Stdin: 0 bytes
parsed pairs:      [("host", "127.0.0.1"), ("port", "8080")]