Skip to content
Select theme

How to read a line from standard input

Short answer: io::stdin().read_line(&mut line) reads the line including its trailing newline, so "Ada" comes back as "Ada\n" — four bytes, not three. line.trim() gives you the text without it.

From a fresh project — cargo new read-line — 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 'Ada\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 'Ada\n' | cargo run -q
bytes: 4
debug: "Ada\n"
hello, Ada
done

Three facts in one run. read_line reads up to and including the newline, which is why "Ada" is four bytes and why {:?} shows the \n that {} hides. len() counts bytes, not characters. And because the string ends with its own newline, println!("hello, {line}") adds a second one: the blank line before done. Nothing is broken; the newline is simply still in there.

$ printf '42\n' | cargo run -q
thread 'main' (4754163) panicked at src/main.rs:7:33:
called `Result::unwrap()` on an `Err` value: ParseIntError { kind: InvalidDigit }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

The newline is not a digit, so parse rejects the whole string and unwrap() turns that Err into the panic above; the blank first line is part of the output. The thread id changes every run, the message doesn’t. With no input at all the kind is Empty instead of InvalidDigit — same panic, same cause.

$ printf '42\n' | cargo run -q
next year you will be 43

trim returns a &str slice of the same string, nothing allocated, with the whitespace off both ends, so the newline goes and the digits stay. It also clears a Windows \r\n, because \r is whitespace too; trim_end_matches('\n') would leave the \r behind. How to trim whitespace and strip characters has the rest of the family, including the to_string() for when the trimmed text has to outlive the string it came from.

$ printf 'Ada\n' | cargo run -q
name: hello, Ada

The prompt needs its own flush(). Stdout is line-buffered, so print! without a newline sits in the buffer until the first println! or the end of the program; run it interactively and you type before the question appears. How to print without a trailing newline covers why. And read_line appends rather than replaces, so a program that asks two questions needs line.clear() between them, or the second answer lands after the first.

$ printf 'Ada\n' | cargo run -q
returned: 4
string: "Ada\n"
trimmed: "Ada"
$ cargo run -q < /dev/null
returned: 0
string: ""
trimmed: ""
$ printf '\n' | cargo run -q
returned: 1
string: "\n"
trimmed: ""

The return value is the byte count, and it is the only thing that tells an empty line from no line: Ok(0) means the input ended (Ctrl-D at a terminal, or a pipe that ran dry) and the string is left as it was. A line that is nothing but a newline is Ok(1). Both trim to "", so when an empty answer needs different handling from a missing one, branch on the count, not the string.

Reading several values from one line of input is the next step in this chapter.