Taking Input in Rust Part 3: Functions

Using functions with Rust along with input-output.

Let’s see how much I flounder while trying to describe functions.

Functions are like the named building blocks, where you put the specific code to do something. You can use whatever blocks you need, and if the code is general enough, you can use these functions with other programs.

I think I did pretty well, all things considered. I miss the building blocks though, I had a ton of fun building things with them. I even considered buying a set, but I don’t have the money for that anymore. Moving on, here are some program examples of functions, with input-output, of course.

Simple programs with functions:

Functions are declared with the fn keyword, and yes, if you didn’t know already, the fn main() line essentially defines the main function in Rust. Much like other languages you might know, you supply the arguments of the functions (if they take any) in parenthesis. However, returning from a function is a little bit different, as we will see later.

Enough yapping. Let’s have some code already!

The program below performs basic addition. The function takes two arguments, adds them, and then returns the result, which gets printed on the command line.

use std::io;

fn add(num1: i32, num2: i32) -> i32 {

    num1 + num2

}

fn main() {

    println!("Enter two numbers to add them");

    let mut num1: String = String::new();

    io::stdin()

        .read_line(&mut num1)

        .expect("Failed to read the line");

    let num1: i32 = num1.trim().parse().expect("Failed to parse");

    let mut num2: String = String::new();

    io::stdin().read_line(&mut num2).expect("Failed to read");

    let num2: i32 = num2.trim().parse().expect("Failed to parse");

    println!("{} + {} equal to {}", num1, num2, add(num1, num2));

}

I used variable shadowing, which I covered in the previous part. If you still need to understand it, then I suggest you read it.

Let’s see how the program performs.

cargo run

Compiling scratch_pad v0.1.0 (E:\rust-projects\scratch_pad)

Finished dev [unoptimized + debuginfo] target(s) in 0.64s

 Running `target\debug\scratch_pad.exe`

Enter two numbers to add them

20

20

20 + 20 equal to 40

cargo run

Finished dev [unoptimized + debuginfo] target(s) in 0.01s

 Running `target\debug\scratch_pad.exe`

Enter two numbers to add them

39

99

39 + 99 equal to 138

The program is working fine; let’s take a look at the function. It is declared with fn keyword, just as I said, and two arguments are passed to it, both of i32 type, which is clear when you look at the type annotations.

This bit “-> i32” tells us that the function will return an i32 type. It is just like C’s types before a function, like int add(int value1, int value2), which tells us that the function will return an integer type.

Unlike other languages, when we return an expression, we don’t need to type the keyword “return” before it. for example, you would do the same function in JavaScript like this:

Function add(num1, num2) {

    Return num1 + num2;

}

But in Rust, we can return the result of that addition without typing “return” before it. of course, Rust does have a return keyword, but it is used to return early from a function, instead of being a sole way to return from a function.

You can modify this function to do any mathematical operation, just remember to change the name. you wouldn’t want to name a function add when it is actually doing subtraction, now would you?

On a side note, I really had a weird feeling typing out a function before main, since I come from the C background, where functions are usually put after the main function, if they are in the same file. This did not affect me during Python or JS, because those languages don’t have a main function at all. I suppose I could have tried the C-style, but since everyone is doing it this way, I’ve decided to stick with it.

Let’s try to understand return with another example:

Due to my poor memory, I can’t remember whether we covered this program previously or not. In any case, the program below tells you whether a number is even or odd, and it does that by dividing the number by 2. If the remainder of that division is 0, then the number is even. If the division is 1, then the number is odd.

The function returns Boolean, true or false, which gets printed on the screen. True for even, false for odd. I actually wanted to make this program nicer, but I got in trouble when I tried to return a string. Strings are complicated, and I’m already sleep deprived. Can we please deal with them at some other time?

use std::io;

fn even_odd(num: i32) -> bool {

    if num % 2 == 0 {

        return true;

    }

    false

}

fn main() {

    println!("Enter a number to know whether it is odd or even");

    let mut num: String = String::new();

    io::stdin()

     .read_line(&mut num)

     .expect("Failed to read");

    let num: i32 = num.trim().parse().expect("Failed to parse");

    println!("{}", even_odd(num));

}

Here, you get to see the early return about which I talked in the previous section. The function returns by the use of the return keyword if the condition is true and the number is even. Otherwise, false is returned, without the use of the return keyword. I hope you have noticed how a semicolon is missing whenever that happens.

Let’s run the program.

cargo run

Compiling scratch_pad v0.1.0 (E:\rust-projects\scratch_pad)

Finished dev [unoptimized + debuginfo] target(s) in 2.65s

 Running `target\debug\scratch_pad.exe`

Enter a number to know whether it is odd or even

39

False

False means 39 is odd.

cargo run

Finished dev [unoptimized + debuginfo] target(s) in 0.01s

 Running `target\debug\scratch_pad.exe`

Enter a number to know whether it is odd or even

1900

true

true means 1900 is even.

So the program is working as intended. Although I used the if statement to show you the early return, this whole thing could be resolved in one line, as we will see in the next program.

I got the idea for this program when I was watching Dragon Ball Super. There are 13 universes in the multiverse of Dragon Ball, and they all exist in pairs. The pair is determined by whether the numbers of those universes equal to 13 or not. For example, universe 1 and universe 12 are a pair, because their sum equals to 13. Whereas universe 2 and 12 are not a pair, because their sum is 14, beyond 13.

For this program, the user enters two numbers, and if their sum equals to 13, they are a pair. Otherwise, they are not a pair, and they are not part of the multiverse.

use std::io;

fn pair_or_not(universe1: i32, universe2: i32) -> bool {

    universe1 + universe2 == 13

}

fn main() {

    println!("Enter two numbers. If their sum equal to 13, then they are one of the pairs of this multiverse!");

    let mut universe1: String = String::new();

    io::stdin()

        .read_line(&mut universe1)

        .expect("Failed to read");

    let universe1: i32 = universe1.trim().parse().expect("Failed to parse");

    let mut universe2: String = String::new();

    io::stdin()

        .read_line(&mut universe2)

        .expect("Failed to read");

    let universe2: i32 = universe2.trim().parse().expect("Failed to parse");

    let flag: bool = pair_or_not(universe1, universe2);

    match flag {

        true => println!("{} + {} equals 13, they are a pair!", universe1, universe2),

        false => println!(

            "{} + {} do not equal to 13. these universes are not pairs.",

            universe1, universe2

        ),

    }

}

Notice how the function still returns Boolean values, even though I did not type anything like return true; or false before the closing curly brace? This is because the comparison operator (==) also returns Boolean values, true if the comparison is equal; false if the comparison is not equal.

Meaning, I can directly put this line:
universe1 and universe2 == 13

And leave out the semicolon, and the whole thing will just work. Then I just used match to print out different things depending on what is returned from the function. Enough yapping, let’s run the program already!

cargo run

Compiling scratch_pad v0.1.0 (E:\rust-projects\scratch_pad)

Finished dev [unoptimized + debuginfo] target(s) in 0.80s

 Running `target\debug\scratch_pad.exe`

Enter two numbers. If their sum equal to 13, then they are one of the pairs of this multiverse!

2

11

2 + 11 equals 13, they are a pair!

2 + 11 equal to 13, that means they are a pair.

cargo run

Compiling scratch_pad v0.1.0 (E:\rust-projects\scratch_pad)

Finished dev [unoptimized + debuginfo] target(s) in 2.83s

 Running `target\debug\scratch_pad.exe`

Enter two numbers. If their sum equal to 13, then they are one of the pairs of this multiverse!

3

7

3 + 7 do not equal to 13. these universes are not pairs.

3 + 7 do not equal to 13, these universes are not pair. They do exist in the multiverse though, since there are at least 12 universes in total.

This comparison operator returning true false bit I actually learned from JS, more specifically from code wars, where people are obsessed with making their code as short as possible. I do think it is better than a bunch of blocks of if else in this case. Though if you need more values than this, you’ll have to create those blocks anyway.

Ideally, I should deal with the case of someone entering values beyond 12, because we don’t have more than 12 universes, and someone entering characters or other values instead of numbers. But I’m not good enough to do that in Rust yet.

Actually, you can put the whole process of taking input in a function like this:

fn takenum() -> i32 {

println!("Enter a number to find out whether it is even or odd");

let mut num: String = String::new();

io::stdin().read_line(&mut num).expect("Failed to read");

let num: i32 = num.trim().parse().expect("Failed to parse");

num

}

I know, I know, I should name it take_num. But my fingers are tired. I don’t wanna reach to dash and press it with shift to create the underline character!

This function does not take any arguments. But it returns the num variable, which is local to its scope, after the whole process of taking input is done. The value then gets saved into another num variable, which is local to the main function, which is then passed to the even_odd() function, which then returns true for even, false for odd numbers. I essentially reduced the main function to just calling a bunch of functions.

I suppose I could have put the printing in a function as well, but I do think that is overkill for this example. I just wanted to show you that it can be done, and to assure myself that I can actually do it.

This concludes the adventures with functions. I do need to improve my knowledge with other parts of rust, before I can write the next parts to this tutorial. But you can be assured, I’m not done writing these notes, and tormenting you with my horrible programs. I will return once I have suitably tormented myself with Rust with too many linked lists.

Did you find this article valuable?

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