How can I read user input in Rust?
Solution 1
In Rust 0.4, use the ReaderUtil
trait to access the read_line
function. Note that you need to explicitly cast the value to a trait type, for example, reader as io::ReaderUtil
:
fn main() {
let mut allLines = ~[];
let reader = io::stdin();
while !reader.eof() {
allLines.push((reader as io::ReaderUtil).read_line());
}
for allLines.each |line| {
io::println(fmt!("%s", *line));
}
}
This answer predates Rust 1.0. Please see the other answers for modern solutions.
Solution 2
Rust 1.x (see documentation):
use std::io;
use std::io::prelude::*;
fn main() {
let stdin = io::stdin();
for line in stdin.lock().lines() {
println!("{}", line.unwrap());
}
}
Rust 0.10–0.12 (see documentation):
use std::io;
fn main() {
for line in io::stdin().lines() {
print!("{}", line.unwrap());
}
}
Rust 0.9 (see 0.9 documentation):
use std::io;
use std::io::buffered::BufferedReader;
fn main() {
let mut reader = BufferedReader::new(io::stdin());
for line in reader.lines() {
print(line);
}
}
Rust 0.8:
use std::io;
fn main() {
let lines = io::stdin().read_lines();
for line in lines.iter() {
println(*line);
}
}
Rust 0.7:
use std::io;
fn main() {
let lines = io::stdin().read_lines();
for lines.iter().advance |line| {
println(*line);
}
}
Solution 3
As of 17 April 2015, from mdcox
on the Firefox Rust IRC channel.
use std::io;
fn main() {
let mut stdin = io::stdin();
let input = &mut String::new();
loop {
input.clear();
stdin.read_line(input);
println!("{}", input);
}
}
Solution 4
In Rust 1.0 and later, you can use the lines
method on anything that implements the std::io::BufRead
trait to obtain an iterator over lines in the input. You could also use read_line
, but using the iterator is more likely what you'd want. Here is a version of the function in the question using iterators; see below for a more detailed explanation. (playground link)
use std::io;
use std::io::prelude::*;
pub fn read_lines() -> Vec<String> {
let stdin = io::stdin();
let stdin_lock = stdin.lock();
let vec = stdin_lock.lines().filter_map(|l| l.ok()).collect();
vec
}
And here's a version that is more like the C++ version in the question, but is not really the idiomatic way to do this in Rust (playground):
use std::io;
use std::io::prelude::*;
pub fn read_lines() -> Vec<String> {
let mut vec = Vec::new();
let mut string = String::new();
let stdin = io::stdin();
let mut stdin_lock = stdin.lock();
while let Ok(len) = stdin_lock.read_line(&mut string) {
if len > 0 {
vec.push(string);
string = String::new();
} else {
break
}
}
vec
}
To obtain something that implements BufRead
, which is needed to call lines()
or read_line()
, you call std::io::stdin()
to obtain a handle to standard input, and then call lock()
on the result of that to obtain exclusive control of the standard input stream (you must have exclusive control to obtain a BufRead
, because otherwise the buffering could produce arbitrary results if two threads were reading from stdin at once).
To collect the result into a Vec<String>
, you can use the collect
method on an iterator. lines()
returns an iterator over Result<String>
, so we need to handle error cases in which a line could not be read; for this example, we just ignore errors with a filter_map
that just skips any errors.
The C++ like version uses read_line
, which appends the read line to a given string, and we then push the string into our Vec
. Because we transfer ownership of the string to the Vec
when we do that, and because read_line
would otherwise keep appending to the string
, we need to allocate a new string for each loop (this appears to be a bug in the original C++ version in the question, in which the same string is shared and so will keep accumulating every line). We use while let
to continue to read until we hit an error, and we break if we ever read zero bytes which indicates the end of the input.
Solution 5
The question is to read lines from standard input and return a vector. In Rust 1.7:
fn readlines() -> Vec<String> {
use std::io::prelude::*;
let stdin = std::io::stdin();
let v = stdin.lock().lines().map(|x| x.unwrap()).collect();
v
}
Jimmy Lu
Hello, I’m Jimmy Lu, a student studying software engineering at the University of Waterloo. I love reading and learning all sorts of interesting programming books and articles. My two favorite topics are low level optimization in C and template meta-programming in C++. My favorite book is The C++ Programming Language. My projects are all hosted on github and I also maintain a blog. You can also view my resume at my website.
Updated on July 09, 2022Comments
-
Jimmy Lu almost 2 years
I intend to make a tokenizer. I need to read every line the user types and stop reading once the user presses Ctrl + D.
I searched around and only found one example on Rust IO which does not even compile. I looked at the
io
module's documentation and found that theread_line()
function is part of theReaderUtil
interface, butstdin()
returns aReader
instead.The code that I would like would essentially look like the following in C++:
vector<string> readLines () { vector<string> allLines; string line; while (cin >> line) { allLines.push_back(line); } return allLines; }
This question refers to parts of Rust that predate Rust 1.0, but the general concept is still valid in Rust 1.0.
-
Jimmy Lu over 11 yearsI don't think I quite understand how cast works in Rust. :-( It doesn't seem all that similar to casts I'm used to in C/C++. What does it mean when you cast something to a trait type? Does it simply instruct the compilers to let you bind those methods from the trait type onto the thing you're casting from? (in this case, it's whatever returns from
stdin()
...) -
Bilal Husain over 11 yearsI am not well familiar with Rust internals, but I guess the cast is for the type checker because the actual method to call is decided at runtime.
-
Jimmy Lu over 11 yearshmm okay. This is the kind of solution that I wanted. So your answer is accepted :-) Thanks!
-
robinst almost 11 yearsSee The future of iterators in Rust on rust-dev for a discussion about how the
for
loop could become simpler in the future (basically get rid of.iter().advance
). -
huon almost 11 yearsThis can actually be
for io::stdin().each_line |line| { .. }
, or usingextra::fileinput
:for fileinput::input |line| { .. }
-
weberc2 about 9 yearsThe rust 1.0.0 version (top) no longer compiles (even when std::io is changed to std::old_io). :/
-
robinst about 9 years@weberc2 Yes, see this rust issue and RFC PR.
-
yagooar about 9 yearsWhen I do
stdin.read_line(input);
, the compiler warns me about this line being not used. -
gsgx almost 9 years@BeyondSora, it would be nice if you could accept the more upvoted answer below so it appears at the top.
-
gsgx almost 9 years@yagooar, it should warn about the result not being used, not the line. That means reading from stdin might have resulted in an error but you're not checking for it.
-
Peter Mortensen about 3 years