TL;DR The closest you have is lines()
, and the reason read_line
works like it does is efficiency. The version that uses lines()
looks like this:
use std::io::{self, BufRead};
fn main() {
// get next line from stdin and print it
let input = io::stdin().lock().lines().next().unwrap().expect("IO error");
println!("{}", input);
}
In general, read_line()
is not designed for use in small interactive programs; there are better ways to implement those.
The read_line
method comes from the generic io::BufRead
trait, and its primary use is reading input, typically redirected from files or other programs, and possibly coming in large quantities. When processing large amounts of data, it is advantageous to minimize the number of allocations performed, which is why read_line
is designed to reuse an existing string. A typical pattern would be:
let mut line = String::new();
while input.read_line(&mut line)? != 0 {
// do something with line
...
line.clear();
}
The number of (re-)allocations is kept minimal, as line
will grow only as needed to accommodate the input lines. Once a typical size is reached, allocations will become very rare, and once the largest line is read, they will disappear altogether. If read_line()
supported the "convenient" interface, then the above loop would indeed look nicer - for example:
while let Some(line) = read_new_line(some_input)? {
// process the line
...
}
...but would require a new allocation and deallocation for each line. In throw-away or learning programs this can be perfectly fine, but BufRead
is intended as a building block for efficient IO, so its read_line
method favors performance over convenience.