Learning Rust 🦀: 04- The basics: Flow Control
Tags: learning, rust, programming, development
Published: 2023-06-11 11:17:14

In this article I'll discuss the main program flow aspects of any programming language, the `conditions` and `loops` and how they are implemented in Rust.

>#### ⚠️ Remember!
You can find all the code snippets for this series in its [accompanying repo](https://github.com/FadyGrAb/rust-learning-series)  
If you don't want to install Rust locally, you can play with all the code of this series in the official [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021) that can be found on its official page. (cargo commands won't run though. But you mostly won't be needing it) 
⚠️⚠️ The articles in this series are loosely following the contents of "The Rust Programming Language, 2nd Edition" by Steve Klabnik and Carol Nichols in a way that reflects my understanding from a Python developer's perspective.

⭐ I try to publish a new article every week (maybe more if the Rust gods 🙌 are generous 😁) so stay tuned 😉. I'll be posting "new articles updates" on [my LinkedIn](https://www.linkedin.com/in/fady-abdelmassih) and [Twitter](https://twitter.com/fadyGrAb).

### Table of Content:
- [Conditions](#conditions)
    - [The _if_ statement](#the-if-statement)
    - [Using _if_ with _let_](#using-if-with-let)
- [Loops](#loops)
    - [The _loop_ keyword](#the-loop-keyword)
    - [Conditional loops with _while_](#conditional-loops-with-while)
    - [Looping with _for_](#looping-with-for)

## Conditions:
Nothing to see here, moving on to `loops` ... Naah! Just kidding 😁
Rust has several condition-checking statements. The most famous is the `if` statement which we will cover here. Later in the series we will discover `match`, a statement used for "_pattern matching_".

### The _if_ statement:
Rust has the standard `if` statement like Python and the other programming languages. I'm assuming that you already know how to code so I won't go into details such as Boolean values, logical operators and comparison operators.
The `if` statement in Rust has the following familiar structure:
```Rust
fn main() {
    let age: u8 = 29;
    if age < 30 {
        println!("Age is below 30");
    } else if age > 30 {
        println!("Age is above 30");
    } else {
        println!("Age is equal to 30");
    }

}
``` 
If you know JavaScript, this structure will be very familiar to you. And it functions as expected too. Except for one small detail 🤔 ... the condition part must be a `Boolean`! No implicit conversions, no type guessing, no nothing! If the condition isn't a Boolean, the program will "_panic_" . So, the following will fail:
```rust
fn main() {
    let age: u8 = 29;
    if age {
        println!("Age is not equal to zero");
    } else {
        println!("Age is equal to zero");
    }
}
```

Instead, you rewrite the statement to show our explicit intention to compare `age` to `0`:
```rust
fn main() {
    let age: u8 = 29;
    if age != 0 {
        println!("Age is not equal to zero");
    } else {
        println!("Age is equal to zero");
    }
}
```
>🦀 New Rust Terminology: "_panic_" means that the program has errored out!

### Using _if_ with _let_:
Sometime you may want to "_conditionally_" set a variable. You can do that combining `if` and `let` in the same statement (remember ... statements and expressions from the last article?). Because blocks in Rust can return their last value, the following is a perfectly legal statement (notice the absence of a semi-colon at the end of each block):
```rust
fn main() {
    let thershold = 50;
    let value = 10;

    let effective_value = if value > thershold {
        value - thershold // No semi-colon
    } else {
        0                 // No semi-colon
    };
    println!("Effective value is {effective_value}")
}

```
This will print the following in stdout:
```bash
Effective value is 0
```
(Play with the value of `value` to get different outputs)
But this functionality comes with a caveat (you might have guessed it by now 😉). Both `if` branches must have the _same type_! So, the following will fail
```rust
    let threshold = 50;
    let value = 10;
    
    let effective_value = if value > threshold {   // Error: expected integer, found '&str'
         value - threshold
    } else {
        "zero"
    };
```
Because `value` is the default integer type (i32) and so as `threshold`, the return value of `value - threshold` is also an `i32`. But for the `else` branch it returns a "_string literal reference_" which will confuse the Rust compiler and causes the program to "_panic_".
>🦀 New Rust Terminology: Rust calls the hard-coded strings in the code as "_string literals_" and they are used inside a Rust program as "_references_". I don't expect you to know what that means 😁 so stay tuned for future articles.

## Loops:
The other aspect of the program flow control is _loops_. Again, as I assume you are already a Rock Star coder, I won't discuss what loops are and how they work. Instead, I'll go just explore loops in Rust.

### The _loop_ keyword:
Rust has the `loop` keyword that technically presents an "infinity-loop" inside your program, so running the following code will freeze your terminal unless you press `ctrl/cmd + c`:
```rust
fn main() {
    loop {}
}
``` 
And as in Python, Rust has the `break` keyword that "_breaks out of a loop_" and the `continue` keyword that "_skips_" the current loop iteration and starts the next one.
```rust
fn main() { 
    loop {
        println!("Enter loop");
        break;
        println!("After break");
    }
    println!("Outside the loop");
}
```
The output of the previous code will be:
```bash
Enter loop
Outside the loop
```
The loop is executed only once (hence the `Enter loop`) then the `break` keyword exited the loop before hitting `println!("After break");` and the second `Outside the loop` is printed out.
Also using the `continue` keyword as follows, will produce another "_infinity-loop_" as the `break` keyword is "_unreachable_".
```rust
fn main() {
    // Will never break!
    loop {
        continue;
        break;  // Unreachable
    }
}
```
As you have seen by now that anything in Rust that uses code blocks "{}", can return values and the `loop` keyword isn't an exception to that! You can use `break <value>` to break out of the loop and return this value.
```rust
fn main() {
    // Returning values from loop
    let mut students_count = 0;

    let class_capacity = loop {
        students_count += 1;

        if students_count >= 30 {
            break students_count;
        }
    };
    println!("The class capacity is {class_capacity}")
}
```
This code will output:
```bash
The class capacity is 30
```
As we saw with `if` and `let`, `loop` also can be used with `let`. In this code, the loop will break at `students_count >= 30` and returns `30` to `class_capacity`.

A Rust program can have "_nested_" `loop` keywords. But this isn't a pretty sight! Luckily, you can name loops to gain some control. For example:
```rust
fn main() {
    let mut base_count_down = 3;

    'count_down: loop {
        let mut base_count_up = 0;

        'count_up: loop {
            base_count_up += 1;

            if base_count_up > 10 {
                break; // breaks from "count_up loop"
            }

            if base_count_down == 0 {
                break 'count_down; // break from "count_down loop"
            }
            println!("Up: {}, Down: {}", base_count_up, base_count_down);
        }
        base_count_down -= 1;
    }
    println!("Loops are terminated!")
}
```
This will produce
```bash
Up: 1, Down: 3
Up: 2, Down: 3
Up: 3, Down: 3
Up: 4, Down: 3
Up: 5, Down: 3
Up: 6, Down: 3
Up: 7, Down: 3
Up: 8, Down: 3
Up: 9, Down: 3
Up: 10, Down: 3
Up: 1, Down: 2
Up: 2, Down: 2
Up: 3, Down: 2
Up: 4, Down: 2
Up: 5, Down: 2
Up: 6, Down: 2
Up: 7, Down: 2
Up: 8, Down: 2
Up: 9, Down: 2
Up: 10, Down: 2
Up: 1, Down: 1
Up: 2, Down: 1
Up: 3, Down: 1
Up: 4, Down: 1
Up: 5, Down: 1
Up: 6, Down: 1
Up: 7, Down: 1
Up: 8, Down: 1
Up: 9, Down: 1
Up: 10, Down: 1
Loops are terminated!
```
As you can see, the `count_up` loop is counting from 1 to 10 and the `count_down` loop is count from 3 to 1.
>⚠️ You may notice that the `base_count_up` variable is being defined at each `count_up` loop iteration. This is legal in Rust as it uses a Rust feature called "_shadowing_" which we will talk about in future articles.

### Conditional loops with _while_:
`while` in Rust works as you expect as in Python and in any other language. The loop will execute provided that the condition is `true`. And like the `if` statement, the `while` condition must be of a Boolean type:
```rust
fn main() {
    let mut number = 10;
    while number != 0 {
        println!("The number is {number}");
        number -= 1;
    }
    println!("Outside of while!")
}
```
The output of the preceding code is:
```bash 
The number is 10
The number is 9
The number is 8
The number is 7
The number is 6
The number is 5
The number is 4
The number is 3
The number is 2
The number is 1
Outside of while!
```

### Looping with _for_:
And last but not least, the friendly neighborhood `for` loop 😉
This too works as you expect like in any language and you can use `for` to iterate over Rust "_collections_" (like arrays and tuples). 
```rust
fn main() {
    // For loops
    let arr = [1, 2, 3, 10, 9, 8];

    for element in arr {
        println!("The array value is {element}")
    }
}
```
This will produce the following:
```bash
The array value is 1
The array value is 2
The array value is 3
The array value is 10
The array value is 9
The array value is 8
```

> ⚠️ We could have just obtained the same result using `while` and an `index` mutable variable. But we should know the exact array length as out-of-range indexes will cause a Rust program to "_panic_"

And like Python, you can use a Rust `Range` to loop a predefined number of times. The below code counts from 10 to 1.
```rust
fn main() {
    // count-down loop
    for num in (1..11).rev() {
        println!("Count-down {num}")
    }
    println!("Go! Go! Go!")
}
```

That's a quick overview of the program flow control in Rust! In the next article, we will put everything together and build our first functional Rust application 🤩. See you then 👋