Skip to content
Select theme

How to read several values from one line of input

Short answer: line.split_whitespace() hands you the fields one at a time; map each through parse and collect into a Vec — or call next() once per value when the count is known.

From a fresh project — cargo new multi-value — replace src/main.rs with each block below and run it with cargo run. The project name only shows up in cargo’s own output. The transcripts pipe the input in (printf '1 2 3\n' | cargo run -q), so the bytes shown are the bytes the command produces; typing the line by hand ends with the same output.

$ printf '1 2 3\n' | cargo run -q
[1, 2, 3]

split_whitespace splits on runs of any whitespace — spaces, tabs — and skips the empty stretches, so a line with a double space in it still gives the same three fields. It also swallows the newline read_line left on the end, which is why there is no trim() here: whitespace at either end of the line produces no fields at all. Each field goes through parse, and collect gathers them into the Vec<i32> the annotation asks for.

Two numbers on a line — a width and a height — don’t need a Vec. split_whitespace returns an iterator, and next() takes one field off it:

$ printf '3 4\n' | cargo run -q
area: 12

next() returns an Option, and it is None once the fields run out. A line with one number panics at the second unwrap() rather than quietly using a wrong value:

$ printf '3\n' | cargo run -q
thread 'main' (5118442) panicked at src/main.rs:9:37:
called `Option::unwrap()` on a `None` value
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

The blank first line and the thread id are part of the output; the id changes every run, the message doesn’t.

map(|part| part.parse().unwrap()) turns a bad field into a panic. Collecting into a Result instead moves that decision into a match:

$ printf '1 2 3\n' | cargo run -q
sum: 6
$ printf '1 2 x\n' | cargo run -q
not a number: invalid digit found in string

collect into Result<Vec<_>, _> stops at the first Err and hands the error back, so the whole line is rejected rather than half-parsed. An empty line yields no fields, which makes it Ok with an empty Vec — the sum is 0, not an error.

$ printf '1 2 3\n' | cargo run -q
split(' '): ["1", "", "2", "3\n"]
split_whitespace: ["1", "2", "3"]

split(' ') cuts on exactly one space, so a double space leaves an empty field, and the newline from read_line stays attached to the last one. Neither "" nor "3\n" parses as an i32 — the first fails as Empty, the second as InvalidDigit. split_whitespace has neither problem, which is why it is the one to reach for. How to read a line from standard input has the newline itself; How to split a string has the rest of the family.

Reading standard input until the end — the loop behind a Unix pipe — is the next step in this chapter.