2.10 Input

In order to do anything really interesting using programming, it would be nice if we had a way to scan the console for user input.

Using modules

It’s about time we start using some more interesting functionality offered by Rust’s standard library. This time around, we are going to use part of its IO module. This piece of the library has methods for checking the console for user input at any given time.

Add this to the top of your main.rs:

use std::io;

This will change the access path to the std::io module. Upon using different functions from inside the std::io, we would usually have had to type out the whole path—including std::io—now we can write just io for the same result.

String

In order to retrieve user input we need to set up a piece of data which can store whatever the user enters into the console—that being a String:

let mut input = String::new();

Many structs throughout the standard library has the ability to be initialized using a sort of constructor—most of the time having a name of new. We can call this using ::—setting a binding equal to that of whatever is returned by String::new.

The String struct is a higher-level type of string than that of the string slice. Usually when we get serious about a string, we make it out of the String struct.

Reading line

After creating a blank string—we can make use of the blank string to read a line of input from the console:

io::stdin().read_line(&mut input);

What this does is create a new Stdin handler upon calling the stdin method on the io. In turn, we call the read_line function located on the Stdin handler—providing it with a mutable reference of the input string, so that the read_line method may change it to the user’s input for us.

References are covered in-depth in the section Borrowing.

There’s however one problem with the above; what if there was an error reading the line? We need a way to check and see if an error has occured. Luckily, the read_line returns a Result, which has a method called expect—calling panic! upon locating an error.

io::stdin().read_line(&mut input)
        .expect("Error reading line.");

The panic! macro prints a message into the console following the exiting of the application. Should an error occur, expect will make sure to panic! with the argument it has been provided.

Finalizing

Let’s put this together into a single piece of code:

use std::io;

fn main()
{
    let mut input = String::new();

    println!("Kindly input a message!");        

    io::stdin().read_line(&mut input)
        .expect("Error reading line.");

    // Print out whatever the user typed
    println!("You entered {}.", input);
}

Upon running you will be presented with the ability to enter a message:

Kindly input a message!
Dog
You typed Dog
.

Hey! There’s a tiny problem. The period fell down to a new line.

Removing whitespace

When we entered Dog into the console—we submitted our input using the enter key on our keyboard. The enter key being pressed registers as \n which is equivalent to a new line.

There's a way we can get rid of any extra whitespace on either side of the string—this we can do using the trim method located on all of Rust’s various different types of strings.

Let’s enter the same code again, but also trim the retrieved string this time:

use std::io;

fn main()
{
    let mut input = String::new();

    println!("Kindly input a message!");

    io::stdin().read_line(&mut input)
            .expect("Error reading line.");

    // Trim of whitespace at the beginning and end of the string
    let input = input.trim();

    // Print out whatever the user typed
    println!("You typed {}.", input);
}

Suddenly the previous console output will look correctly:

Kindly input a message!
Dog
You typed Dog.

Parsing

Quite oftenly, you’re going to want to turn the string of input we were given into a numeric type. For this, we can make use of the parse method located under all different types of strings. We still need to trim the string, as any other characters than that of numbers will generate an error. Let’s expand on the line where we trimmed the string in the previous example:

let input: i32 = input.trim().parse()
        .expect("Not an integer.");

Notice how we had to specify the type of input this time around? This is for the fact that the parse method will not know what to parse input into otherwise. Perhaps it’s a signed integer, perhaps it’s an unsigned one—perhaps it’s even a floating-point number—who knows?

The parse method returns a Result, just like read_line. This means we can use the expect method on it to check for errors. In this case, an error will occur if we can’t parse the string correctly—if there’s any character or glyph not being a number contained by the string.

With the integer acquired, we can use it for calculations of any kind—even check it for equality with other numbers had we wanted to.

Exercises

  • First input one number of type i32 into the console, then another of the same type. Add the numbers together and print out the output into the console.
  • Clear the project and do the same for division—make sure there’s an awful error message being generated upon attempting to divide the first number by zero.

Moreover

The ability to scan for user input creates the possibility of making interactive applications. Who wouldn’t want to have the ability to ask their users for what the want? This world does not revolve around us!

You are now eligible for Calculator.

Random