How can I read a single line from stdin?
RustRust Problem Overview
I'm asking for the equivalent of fgets()
in C.
let line = ...;
println!("You entered: {}", line);
I've read https://stackoverflow.com/questions/13579266/how-to-read-user-input-in-rust, but it asks how to read multiple lines; I want only one line.
I also read https://stackoverflow.com/questions/28528998/how-do-i-read-a-single-string-from-standard-input, but I'm not sure if it behaves like fgets()
or sscanf("%s",...)
.
Rust Solutions
Solution 1 - Rust
In https://stackoverflow.com/questions/13579266/how-to-read-user-input-in-rust you can see how to iterate over all lines:
use std::io::{self, BufRead};
fn main() {
let stdin = io::stdin();
for line in stdin.lock().lines() {
println!("{}", line.unwrap());
}
}
You can also manually iterate without a for-loop:
use std::io::{self, BufRead};
fn main() {
let stdin = io::stdin();
let mut iterator = stdin.lock().lines();
let line1 = iterator.next().unwrap().unwrap();
let line2 = iterator.next().unwrap().unwrap();
}
You cannot write a one-liner to do what you want. But the following reads a single line (and is exactly the same answer as in https://stackoverflow.com/questions/28528998/how-do-i-read-a-single-string-from-standard-input):
use std::io::{self, BufRead};
fn main() {
let stdin = io::stdin();
let line1 = stdin.lock().lines().next().unwrap().unwrap();
}
You can also use the text_io
crate for super simple input:
#[macro_use] extern crate text_io;
fn main() {
// reads until a \n is encountered
let line: String = read!("{}\n");
}
Solution 2 - Rust
If you truly want the equivalent to fgets
, then @Gerstmann is right, you should use Stdin::read_line
. This method accepts a buffer that you have more control of to put the string into:
use std::io::{self, BufRead};
fn main() {
let mut line = String::new();
let stdin = io::stdin();
stdin.lock().read_line(&mut line).unwrap();
println!("{}", line)
}
Unlike C, you can't accidentally overrun the buffer; it will be automatically resized if the input string is too big.
The answer from @oli_obk - ker is the idiomatic solution you will see most of the time. In it, the string is managed for you, and the interface is much cleaner.
Solution 3 - Rust
Read a single line from stdin
:
let mut line = String::new();
std::io::stdin().read_line(&mut line)?; // including '\n'
You may remove '\n'
using line.trim_end()
Read until EOF:
let mut buffer = String::new();
std::io::stdin().read_to_string(&mut buffer)?;
Using implicit synchronization:
use std::io;
fn main() -> io::Result<()> {
let mut line = String::new();
io::stdin().read_line(&mut line)?;
println!("You entered: {}", line);
Ok(())
}
Using explicit synchronization:
use std::io::{self, BufRead};
fn main() -> io::Result<()> {
let stdin = io::stdin();
let mut handle = stdin.lock();
let mut line = String::new();
handle.read_line(&mut line)?;
println!("You entered: {}", line);
Ok(())
}
If you interested in the number of bytes e.g. n
, use:
let n = handle.read_line(&mut line)?;
or
let n = io::stdin().read_line(&mut line)?;
Try this:
use std::io;
fn main() -> io::Result<()> {
let mut line = String::new();
let n = io::stdin().read_line(&mut line)?;
println!("{} bytes read", n);
println!("You entered: {}", line);
Ok(())
}
See doc
Solution 4 - Rust
if you want to leave the for
-loop at some point
use std::io::{self, BufRead};
fn main() {
let stdin = io::stdin();
for line in stdin.lock().lines() {
match line {
Err(_) => break, // with ^Z
Ok(s) => println!("{}", s),
}
}
println!("fin");
}