0

I want to take 2 user inputs, height and width:

fn main() {
    let mut w = String::new();
    let mut l = String::new();
    println!("Enter the width");
    io::stdin().read_line(&mut w).expect("failed to read input");
    let w: i32 = w.trim().parse().expect("invalid input");

    println!("Enter the length");
    io::stdin().read_line(&mut l).expect("failed to read input");
    let l: i32 = l.trim().parse().expect("invalid input");

    println!("width {:?}", w);
    println!("length{:?}", l);
}

Is there a shorter way to achieve this?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Abhinab k
  • 21
  • 2
  • 6
  • 2
    You can wrap the repeated lines in a function. But apart from that: it looks terse and idiomatic to me. There are several steps here (including error handling) and Rust requires you to be explicit about every step. – Thomas Aug 25 '20 at 14:24
  • See also [How do I read multiple integers from a single line of stdin?](https://stackoverflow.com/q/39439582/155423); [Weird behaviour when using read_line in a loop](https://stackoverflow.com/q/45232943/155423) – Shepmaster Aug 25 '20 at 14:57

2 Answers2

2

Handling input from the terminal is not really fun, so a number of crates try to make is shorter/easier/more luxurious.

A possible candidate is rprompt:

let reply = rprompt::prompt_reply_stdout("Password: ").unwrap();
println!("Your reply is {}", reply);

That is probably just a shortcut to Thomas' advice of wrapping all that stuff in a function of your own. I prefer using crates because they allow for nice little features like enabling the user to correct their input when they made a mistake...

prompty may be worth looking at.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Bernhard
  • 4,272
  • 1
  • 13
  • 23
  • Not sure how much you want to turn this answer into "here's a list of crates", but `text_io` is another one. – trent Aug 25 '20 at 14:42
  • I think that it is good to have alternatives and I do not think that the crates.io search function helps that much, so yes: keep them coming ;-) – Bernhard Aug 25 '20 at 15:46
2

An idiomatic way to provide user input is to entirely avoid quizzing the user. Instead, accept short inputs through command-line arguments and long inputs through files or the standard input. In this case you can use clap to parse the command line:

#[macro_use]
extern crate clap;

use clap::{App, Arg};

fn main() {
    let matches = App::new("My Program")
        .arg(Arg::with_name("width").required(true))
        .arg(Arg::with_name("height").required(true))
        .get_matches();

    let width = value_t!(matches, "width", i32).unwrap();
    let height = value_t!(matches, "height", i32).unwrap();

    println!("{} {}", width, height);
}

This will allow you to invoke the program as my_program 10 20, to edit the invocation using advanced shell editing facilities, remember it in shell history, or automate it with scripts.

Compared to requiring the user to type in the values over and over for each invocation, without readline or history, it's more user-friendly, more professional, and it matches the best practices of the ecosystem.

user4815162342
  • 141,790
  • 18
  • 296
  • 355