Rust Fundamentals - Part 2

Photo by kazuend on Unsplash

Rust Fundamentals - Part 2

Control Flow

Control Flow is the basic building block of programming language. That represents the order in which elements of a computer program - instructions, statements and function calls are executed and evaluated.

IF Expression

If expression allows you to branch the code depending on the conditions.

If the given condition is met then executes the following code. If the given condition is not met do not execute the code.

Let's try a few examples of If expressions. Head to Rust playground and start typing the below code.

fn main(){
    let number = 20;
    if number != 20{
        println! ("Number not equal to 20")
    }else{
        println! ("Number equal to 20")
    }
}

In the above example, the conditions check whether or not the variable number is not equal to 20. If the condition is valid code immediately after the condition inside curly brackets is executed. If the condition is false code inside the else block is executed. If you don’t provide an else expression and the condition is false, the program will just skip the if block and move on to the next bit of code.

Rust will not automatically try to convert non-Boolean types to a Boolean. So condition should always evaluate to boolean. The below example demonstrates what happens when you don't give conditions that don't evaluate to boolean:

fn main(){
    let number = 20;
    if number{
        println! ("Number not equal to 20")
    }else{
        println! ("Number equal to 20")
    }
}
error[E0308]: mismatched types
 --> src/main.rs:3:8
  |
3 |     if number{
  |        ^^^^^^ expected `bool`, found integer

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to a previous error

Handling multiple conditions with else if

We can use multiple conditions by combining if and else in an else if expression:

Example:

fn main() {
    let number = 6;

    if number % 4 == 0 {
        println!("number is divisible by 4");
    } else if number % 3 == 0 {
        println!("number is divisible by 3");
    } else if number % 2 == 0 {
        println!("number is divisible by 2");
    } else {
        println!("number is not divisible by 4, 3, or 2");
    }
}

Output:

the number is divisible by 3

When this program executes, it checks each if expression in turn and executes the first body for which the condition holds true. Note that even though 6 is divisible by 2, we don’t see the output number divisible by 2, nor do we see the number is not divisible by 4, 3, or 2 texts from the else block. That’s because Rust only executes the block for the first true condition, and once it finds one, it doesn’t even check the rest.

Using if in a let Statement

As if is an expression which evaluates to some value. So we can assign the outcome of the if expression to a variable using the let keyword.

fn main() {
    let condition = false;
    let number = if condition { 5 } else { 6 };

    println!("The value of number is: {number}");
}

The value of the number variable is bound to a value based on the conditional outcome Output:

The value of number is: 6

Remember that blocks of code evaluate to the last expression in them, and numbers by themselves are also expressions. In this case, the value of the whole if expression depends on which block of code executes. This means the values that have the potential to result from each arm of the if must be the same type.

If the types are mismatched, as, in the following example, we’ll get an error:

fn main() {
    let condition = false;
    let number = if condition { 5 } else { "six" };

    println!("The value of number is: {number}");
}

The if and else arms have incompatible value types, and Rust indicates exactly where to find the problem in the program.

   Compiling playground v0.0.1 (/playground)
error[E0308]: `if` and `else` have incompatible types
 --> src/main.rs:3:44
  |
3 |     let number = if condition { 5 } else { "six" };
  |                                 -          ^^^^^ expected integer, found `&str`
  |                                 |
  |                                 expected because of this

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to previous error

The expression in the if block evaluates to an integer, and the expression in the else block evaluates to a string. This won’t work because variables must have a single type, and Rust needs to know at compile time what type the number variable is.

Loops

Loops are programming elements that repeat a portion of code a set number of times until the desired process is complete. Repetitive tasks are common in programming, and loops are essential to save time and minimize errors.

In Rust, we can use the loop keyword to execute a block of code over and over again forever or until the set conditions are met.

fn main() {
    loop {
        println!("again!");
    }
}

When we run this program, we’ll see again! printed over and over continuously until we stop the program manually.

$ cargo run
   Compiling loops v0.1.0 (file:///projects/loops)
    Finished dev [unoptimized + debuginfo] target(s) in 0.29s
     Running `target/debug/loops`
again!
again!
again!
again!
^Cagain!

We can break out of the loop by using the break keyword and also we can use the continue keyword to skip over the remaining iteration of the loop and move to the next.

We can also return values from loops. One of the uses of a loop is to retry an operation you know might fail, such as checking whether a thread has completed its job. You might also need to pass the result of that operation out of the loop to the rest of your code. To do this, you can add the value you want to be returned after the break expression you use to stop the loop; that value will be returned out of the loop so you can use it, as shown here:

fn main() {
    let mut counter = 0;

    let result = loop {
        counter += 1;

        if counter == 10 {
            break counter * 2;
        }
    };

    println!("The result is {result}");
}

Output

The result is 20

Loop Labels to Disambiguate Between Multiple Loops

When you have loops within loops it will be a little difficult to handle continue and breaks in the nested loops for that in rust we have loop labels. These labels point out the loops which are defined. If you want to continue or break a particular loop in nested loops we can use labels. Loop labels must begin with a single quote. Here’s an example with two nested loops:

fn main() {
    let mut count = 0;
    'counting_up: loop {
        println!("count = {count}");
        let mut remaining = 10;

        loop {
            println!("remaining = {remaining}");
            if remaining == 9 {
                break;
            }
            if count == 2 {
                break 'counting_up;
            }
            remaining -= 1;
        }

        count += 1;
    }
    println!("End count = {count}");
}

Output

count = 0
remaining = 10
remaining = 9
count = 1
remaining = 10
remaining = 9
count = 2
remaining = 10
End count = 2

While Loop

It's very often when programming you need to evaluate a condition within a loop. While loop runs until the given specified condition is false.

fn main() {
    let mut number = 3;

    while number != 0 {
        println!("{number}!");

        number -= 1;
    }

    println!("LIFTOFF!!!");
}

Until the condition mentioned is true while will execute the code block.

3!
2!
1!
LIFTOFF!!!

For Loop

The for loop executes the code block for a specified number of times. It can be used to iterate over a fixed set of values, such as an array. The syntax of the for loop is as given below:

for temp_variable in lower_bound..upper_bound {
   //statements
}

Example:

fn main(){
   for x in 1..11{ // 11 is not inclusive
      if x==5 {
         continue;
      }
      println!("x is {}",x);
   }
}

Output

x is 1
x is 2
x is 3
x is 4
x is 6
x is 7
x is 8
x is 9
x is 10

Looping over a collection of items using for loop.

fn main() {
    let a = [10, 20, 30, 40, 50];

    for element in a {
        println!("the value is: {element}");
    }
}

Here for loop iterates over each element of the array and prints it.

the value is: 10
the value is: 20
the value is: 30
the value is: 40
the value is: 50

💫 You Made It!!

In this post, we learned about if expressions and loops. Also looked through various samples of how to use them in programming. To get good hands-on in control flow try writing a small program to Generate the nth Fibonacci number. In the upcoming post, we will cover the rest of the fundamentals of rust. If you run into any issues with any part of this post, please leave a comment so that I can update the content to be more clear. If you like this post please do follow me on Hashnode and subscribe to my newsletter for future updates.

Did you find this article valuable?

Support The Missing Semicolon by becoming a sponsor. Any amount is appreciated!