How to read an integer input from the user in Rust 1.0?
Asked Answered
R

8

37

Existing answers I've found are all based on from_str (such as Reading in user input from console once efficiently), but apparently from_str(x) has changed into x.parse() in Rust 1.0. As a newbie, it's not obvious how the original solution should be adapted taking this change into account.

As of Rust 1.0, what is the easiest way to get an integer input from the user?

Rosmunda answered 20/5, 2015 at 16:17 Comment(0)
S
72

Here is a version with all optional type annotations and error handling which may be useful for beginners like me:

use std::io;

fn main() {
    let mut input_text = String::new();
    io::stdin()
        .read_line(&mut input_text)
        .expect("failed to read from stdin");

    let trimmed = input_text.trim();
    match trimmed.parse::<u32>() {
        Ok(i) => println!("your integer input: {}", i),
        Err(..) => println!("this was not an integer: {}", trimmed),
    };
}
Shanta answered 20/5, 2015 at 16:55 Comment(3)
what about the use of unwrap()? how do you handle parse errors, and reporting them to stderr?Brewmaster
@Brewmaster the errors are reported by handling Result produced by parse() with a match. unwrap() would cause the program to panic.Serviceberry
This "reads a line and parses the entire line as an integer" rather than "reads a next single integer", which is far from cin >> i in C++.Tan
M
25

If you are looking for a way to read input for the purpose of competitive programming on websites like codeforces where you do not have access to text_io, this solution is for you.

I use the following macro to read different values from stdin:


#[allow(unused_macros)]
macro_rules! read {
    ($out:ident as $type:ty) => {
        let mut inner = String::new();
        std::io::stdin().read_line(&mut inner).expect("A String");
        let $out = inner.trim().parse::<$type>().expect("Parsable");
    };
}

#[allow(unused_macros)]
macro_rules! read_str {
    ($out:ident) => {
        let mut inner = String::new();
        std::io::stdin().read_line(&mut inner).expect("A String");
        let $out = inner.trim();
    };
}

#[allow(unused_macros)]
macro_rules! read_vec {
    ($out:ident as $type:ty) => {
        let mut inner = String::new();
        std::io::stdin().read_line(&mut inner).unwrap();
        let $out = inner
            .trim()
            .split_whitespace()
            .map(|s| s.parse::<$type>().unwrap())
            .collect::<Vec<$type>>();
    };
}
  

Use it as follows:


fn main(){
   read!(x as u32);
   read!(y as f64);
   read!(z as char);
   println!("{} {} {}", x, y, z);

   read_vec!(v as u32); // Reads space separated integers and stops when newline is encountered.
   println!("{:?}", v);
}

Metacarpal answered 25/7, 2019 at 10:40 Comment(2)
Marvelous!! I searched 3 months for thisTarbes
I overloaded a single "input!(..)" macro and added an entry for ([$type:ty; $x:expr] as $out:pat_param) for reading things like input!([f64; 3] as [a, b, c]); Parsing inputs is so much cleaner with this. Thanks a lot!Des
T
15

Probably the easiest part would be to use the text_io crate and write:

#[macro_use]
extern crate text_io;

fn main() {
    // read until a whitespace and try to convert what was read into an i32
    let i: i32 = read!();
    println!("Read in: {}", i);
}

If you need to read more than one value simultaneously, you might need to use Rust nightly.

See also:

Tavey answered 20/5, 2015 at 16:32 Comment(5)
I think it does run on stable if you only need to read one value at a time.Rossman
text_io dev here. @VladimirMatveev is right, text_io runs on stable if you don't read tuples but just a single value per read!() invocation. It actually requires nightly for multiple values. I'll update the github description.Rockingham
Is there a better option now? After 3 years of Rust being out, I would assume there would be better ways of inputting values into integer variables. The solution suggested is what I encountered in the rust book, but its lengthy and feels a bit overkill for input. The text_io suggestion is great, but I'm not able to print statements out from functions before using read!()Schmit
@joe_04_04 What do you mean by "print statements out from functions before using read!() ?Tavey
@DanielFath, if I use println!() before trying to use read!() from text_io, items that are supposed to print from println!() do not get printed until after the read!() method.Schmit
B
14

Here are a few possibilities (Rust 1.7):

use std::io;

fn main() {
    let mut n = String::new();
    io::stdin()
        .read_line(&mut n)
        .expect("failed to read input.");
    let n: i32 = n.trim().parse().expect("invalid input");
    println!("{:?}", n);

    let mut n = String::new();
    io::stdin()
        .read_line(&mut n)
        .expect("failed to read input.");
    let n = n.trim().parse::<i32>().expect("invalid input");
    println!("{:?}", n);

    let mut n = String::new();
    io::stdin()
        .read_line(&mut n)
        .expect("failed to read input.");
    if let Ok(n) = n.trim().parse::<i32>() {
        println!("{:?}", n);
    }
}

These spare you the ceremony of pattern matching without depending on extra libraries.

Bicycle answered 12/4, 2016 at 14:3 Comment(7)
Come on, it's clearly different, and a complete answer makes it easier for the reader.Bicycle
It looks pretty identical to the accepted answer to me.Crackbrain
Yeah, you have to get a string from the user and store that in a variable, that part is the same. The parsing part is more concise, as explained in my answer.Bicycle
The parsing part is more concise — a comment along the lines of "use Option::expect instead of match to be more concise and fail in cases of error" would be equivalent. a complete answer makes it easier for the reader — this answer is missing the required use std::io and fn main that the accepted answer has and a true beginner would want.Crackbrain
Yeah, fair enough.Bicycle
To be clear, feel free to leave the answer, other people may find it useful and upvote it. So long as there's prose to describe why it's different and better, it's a valid answer!Crackbrain
@Crackbrain its not the same for a beginnerHolter
P
4

parse is more or less the same; it’s read_line that’s unpleasant now.

use std::io;

fn main() {
    let mut s = String::new();
    io::stdin().read_line(&mut s).unwrap();

    match s.trim_right().parse::<i32>() {
        Ok(i) => println!("{} + 5 = {}", i, i + 5),
        Err(_) => println!("Invalid number."),
    }
}
Personalize answered 20/5, 2015 at 16:42 Comment(0)
R
3

You can create an extension method if you want a simple syntax:

use std::error::Error;
use std::io;
use std::str::FromStr;

trait Input {
    fn my_read<T>(&mut self) -> io::Result<T>
    where
        T: FromStr,
        T::Err: Error + Send + Sync + 'static;
}

impl<R> Input for R where R: io::Read {
    fn my_read<T>(&mut self) -> io::Result<T>
    where
        T: FromStr,
        T::Err: Error + Send + Sync + 'static,
    {
        let mut buff = String::new();
        self.read_to_string(&mut buff)?;

        buff.trim()
            .parse()
            .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))
    }
}

// Usage:

fn main() -> io::Result<()> {
    let input: i32 = io::stdin().my_read()?;

    println!("{}", input);

    Ok(())
}
Ridenour answered 19/8, 2019 at 10:26 Comment(0)
S
2

I would definitely use the file system Rust-Lang provides std::fs (See more here: https://doc.rust-lang.org/stable/std/fs/) But more particularly https://doc.rust-lang.org/stable/std/fs/fn.read_to_string.html

Let's say you just want to read input of a text file, try this :

use std::fs
or
use std::fs::read_to_string

fn main() {
    println!("{}", fs::read_to_string("input.txt"));   
}
Shoat answered 7/12, 2019 at 20:36 Comment(0)
W
2

you can try this piece of code

fn main() {

    let mut line  = String::new();

    // read input line string and store it into line
    std::io::stdin().read_line(&mut line).unwrap();

    // convert line to integer
    let number : i32 = line.trim().parse().unwrap();

    println!("Your number {}",number);
}

now you can write a function for taking user input and use it everytime like below

fn main() {

    let first_number = get_input();
    let second_number = get_input();

    println!("Summation : {}",first_number+second_number);

}

fn get_input() -> i32{

    let mut line  = String::new();
    std::io::stdin().read_line(&mut line).unwrap();
    let number : i32 = line.trim().parse().unwrap();
    return number ;
}
Wsan answered 9/10, 2021 at 15:13 Comment(1)
Is there a way for this to work for any data type instead of making one function for each type?Tarbes

© 2022 - 2024 — McMap. All rights reserved.