How can I read a single line from stdin in Rust?

I'm asking for the equivalent of fgets() in C.

let line = ...;
println!("You entered: {}", line);

I've read How to read user input in Rust?, but it asks how to read multiple lines; I want only one line.

I also read How do I read a single String from standard input?, but I'm not sure if it behaves like fgets() or sscanf("%s",...).

6 Answers

In 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 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");
}
4

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.

0

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

Starting with Rust 1.62, you can use Stdin::lines() to get one line (of input) using only one line (of code):

fn main() { let line = std::io::stdin().lines().next().unwrap().unwrap();
}

Although Stdin::lines() can be used for a single line, it would typically be used for getting multiple. It simplifies this use case so that it is no longer necessary to worry about lifetimes and locking:

fn main() { for line in std::io::stdin().lines() { println!("line: {}", line.unwrap()); }
}

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");
}

You can roll your own macro.

macro_rules! read_line { () => { { let mut str = String::new(); std::io::stdin().read_line(&mut str).expect("!"); str } };
}
fn main () { println!("What is your name?"); let name = read_line!(); println!("Hello {}.", name.trim());
}

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like