Input Output in Rust Part 1

Input Output in Rust Part 1

Taking input, and printing it back in Rust. We will also see how taking input is in C compare to Rust, because I don’t know C++ that well.

If you go around the web reading the tutorials in Rust, you won’t find many simple input output programs there, like you would for C. Now, you can attribute this to the young age of the language compared to C, since in 2022, it has reached its teen years already. (Nothing like a programming language appearing year to remind you of your age, eh?) Also, those tutorials are written for some advanced tasks, for which someone hardly is going to ask you for keyboard input over a command line window.

So, there’s isn’t much incentive to talk about that info. But I do feel that when you start out with a language, these small input and output programs are great for learning things, especially cooking up a quick program to test a few things on the command line. It also helps that typing out something is faster than constantly changing the hardcoded values, and then re-compiling the program to see its output. And as I said in my introduction post, when you write about something, you realize you don’t know as much as you thought. So these tutorials will also help me in improving myself.

And thus, I’m writing this series. For this first part, we will get keyboard input from the user over the command line, and show them what they typed out. As the wise computer from Courage the Cowardly Dog points out, “Everything you say bounces off me, and sticks to you.”

First, printing some Strings:

We will ask the user to type their name, and then print back their name in the following programs. Let’s start with how you might do that in C, just for comparisons. I won’t do that in the following parts after this one.

#include <stdio.h>
int main (void) {
    char name[12]; // The array to hold the characters for the name of the user.
    puts("Enter your name"); // Prompt to enter something, in this case, the name of the user. This isn’t strictly necessary, and you can skip this. But prompting is necessary when you want to tell the user that there’s something they should type out.
    scanf("%s", name); // Receiving input through scanf().
    printf("%s is your name\n", name); // Printing out the name.
    return 0;
}

Now, let’s do the same task in Rust. Aside from the language differences, the program below is the same.

use std::io;
fn main() {
    println!("Enter your name");
        let mut name = String::new(); // Constructing an empty String.
    io::stdin().read_line(&mut name).expect("Failed to read your name, sorry!");
    println!("{} is your name.", name);
}

You will immediately notice how different the second program is compared to the C program. Both programs produce the same output, given below:

Enter your name Tanish Tanish is your name.

The main difference is that in C, you can get away with a lot of things, for example not handling errors. Whereas in Rust, you have to handle errors. Granted, you can get away with that too; for example, you can remove the expect(“Failed to read your name”); line entirely. The program will still run. But you’ll get a warning.

warning: unused Result that must be used --> src\main.rs:5:5 | 5 | io::stdin().read_line(&mut name); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: #[warn(unused_must_use)] on by default = note: this Result may be an Err variant, which should be handled

warning: hello_user (bin "hello_user") generated 1 warning Finished dev [unoptimized + debuginfo] target(s) in 1.15s Running target\debug\hello_user.exe Enter your name, and see it get printed! Tanish Tanish is your name.

So you see, even when I commented out the expect() line, the program still runs as expected, even with the warning.

You can type out anything you want there, like emojis, text in Hindi, and even numbers. And they’ll get printed without error. I’m sure there are ways to handle the emojis and numbers, because we do want the user to enter their name, whether they enter it in Hindi or English. But for now, my knowledge is not good enough to handle those cases.

Note: the author is an idiot. It is a wonder that he can even write this much.

The error handling comes in useful when you’re dealing with numbers, as we will see in the next section.

Printing numbers entered by user:

The same program as above will be used for this section, this time with numbers. The user enters a number; the program prints it back. Let’s see how you perform this task in C. And please, keep your “I C” jokes to yourselves!

#include <stdio.h>
int main (void) {
int num = 0;
    puts("Enter a number");
scanf("%d", &num);
    printf("The number is %d\n", num);
    return 0;
}

And now, for the Rust implementation:

use std::io;
fn main() {
    println!("Enter a number");
    let mut num: String = String::new();
    io::stdin().read_line(&mut num).expect("Failed to read the number");
    let num: i32 = num.trim().parse().expect("Failed to parse");
    println!("The number is {}", num);
}

Once again, both programs work identically when run:

Enter a number 9 The number is 9.

Though you will notice that things are again, much more involved with Rust. For example, the variable num is of String type, denoted by its annotation. Whereas in C, you can directly take input to an integer type variable. Since we already dealt with expect() previously, let’s talk about the other new methods we used in this new program. But before we can do that, we’ll need to talk about variable shadowing. This allows us to use the same variable name for different values. As you can see, the original num variable is annotated with String, while the shadowing variable is annotated with i32, which is a type to hold integer values in Rust. We have to use String to take the numbers in Rust, because the String::new() thing is not implemented for i32. So you can’t do something like i32::new().

Note: we get another demonstration of the idiocy of this author, as he doesn’t even know what exactly String::new() is, calling it a thing instead of a constructor.

While the first num variable is annotated with String, it is not necessary. I just did it to prove a point (which I forgot), and because I just like annotating my variables, whenever possible. The second num shadowing variable has to be annotated with the type of its value, because the compiler produces an error otherwise.

The trim() method is used for removing white spaces and \n from the String which is necessary before you parse String into number, and the parse() method is used for parsing the String number into number.

Let’s move on to error handling. In the C version of this program, when you enter a character different from a number, you get the following result:

$test Enter a number ; The number is 0.

$test Enter a number A The number is 0.

The program prints the number 0, because I’ve initialized the num variable with the number 0. If I hadn’t done that, it would have printed some random garbage value. But what about Rust?

Finished dev [unoptimized + debuginfo] target(s) in 2.72s
 Running `target\debug\print_num.exe`

Enter a number a thread 'main' panicked at 'Failed to parse: ParseIntError { kind: InvalidDigit }', src\main.rs:6:39 note: run with RUST_BACKTRACE=1 environment variable to display a backtrace error: process didn't exit successfully: target\debug\print_num.exe (exit code: 101)

Notice the error? That expect() may not have been so useful in the String version of this program. But it is certainly proving to be useful here, working as an input validator for us, which we would have needed to do explicitly in C, with more code. It is still incomplete error handling though, because the program crashes instead of giving the user a chance of inputting the right value.

Now, I’m aware of my piss-poor explanations of the use of the methods used in Rust programs above. so, here are the documentation links for stdin(), read_line(), parse(), expect(), and trim().

Anyway, let’s conclude this part here. In the next part, we will work with user input, along with control flow. I hope you enjoyed reading this, even though I lack knowledge in so many things here. You can visit my other blog here, where I talk about non-programming topics.

Did you find this article valuable?

Support Tanish Shrivastava by becoming a sponsor. Any amount is appreciated!