Control flow in Rust
Tags: rust, beginners, programming, tutorial
Published: 2024-02-06 14:41:00

In this lesson, we'll cover the basic control flow in Rust. We'll cover the following topics:

- if expressions
- match
- loop expressions
- while expressions
- for expressions

At the end, we'll have a simple exercise to practice what we've learned.

If you prefer a video version
{% youtube 2w_FTiD74JI %}

<!-- <iframe width="905" height="510" src="https://www.youtube.com/embed/2w_FTiD74JI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe> -->

A recap is available on [GitHub](https://youtu.be/2w_FTiD74JI) (link available in the video description) 

## Control Flow

Control flow is the order in which different parts of a program are executed. 

This is not a concept unique to Rust, but it's a fundamental concept in programming.

Let's start with the most basic example and work our way up.


## if expressions

The if expression works just like it does in other languages: it evaluates the condition, and if it’s true, it executes the block of code associated with it. Let’s look at a simple example:

```rust
fn main() {
    let number = 3;

    if number < 5 {
        println!("condition was true");
    } else {
        println!("condition was false");
    }
}
```

[![Control flow in Rust - Rust programming tutorial](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k4b06v6paqxhh2uzri2f.png)](https://youtu.be/2w_FTiD74JI)

This program prints the condition as true because the value of the number is less than 5. If we change the value of the number to something else, like 6, then the program will print the condition as false instead.

We can also use if in a let statement to bind the value to a variable conditionally. The variable's value would be the value of the expression that matches the if. Here’s an example:

```rust
fn main() {
    let condition = true;
    let number = if condition {
        5
    } else {
        6
    };

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

The number variable will be bound to a value based on the outcome of the if condition. Because the condition is true, the value bound to the number variable is 5. If the condition had been false, the value would have been 6. 

[![Control flow in Rust - Rust programming tutorial](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2quxvh26b7azlci32gy7.png)](https://youtu.be/2w_FTiD74JI)

## Nested if expressions

We can also use if expressions in a nested manner. For example:

```rust
fn main() {
    let num = 15;

    if num % 2 == 0 {
        println!("{} is even", num);
    } else {
        println!("{} is odd", num);

        if num > 10 {
            println!("{} is also greater than 10", num);
        } else {
            println!("{} is not greater than 10", num);
        }
    }
}
```

If we put 16, the output will be:

```bash
16 is even
```

This is because 16 is even, and the nested if is not executed.

[![Control flow in Rust - Rust programming tutorial](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g5707q3bekqtdqr6x7m9.png)](https://youtu.be/2w_FTiD74JI)

## && and ||

We can also use && and || to combine multiple conditions. For example:

```rust
fn main() {
    let a = 10;
    let b = 5;
    let c = 20;

    // Using && (AND) to check if 'a' is > than 'b' AND 'b' is > than 'c'
    if a > b && b > c {
        println!("a is greater than b and b is greater than c");
    } else {
        println!("Condition with && not met");
    }

    // Using || (OR) to check if 'a' is > than 'b' OR 'b' is > than 'c'
    if a > b || b > c {
        println!("At least one condition with || is met");
    } else {
        println!("The condition with || is not met");
    }
}
```

In this case, the output will be:

```bash
Condition with && not met
At least one condition with || is met
```

[![Control flow in Rust - Rust programming tutorial](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m1jwy3bj7wvg8oapzspa.png)](https://youtu.be/2w_FTiD74JI)

## Match in Rust

The match keyword compares a value against a series of patterns and then executes code based on which pattern matches. Patterns can be made up of literal values, variable names, wildcards, and many other things. The power of match comes from the expressiveness of the patterns and the fact that the compiler confirms that all possible cases are handled.

We'll have a dedicated lesson for match, but here's a simple example

```rust
fn main() {
    
    //with enum, we can define a type with a fixed set of values
    enum Coin {
        Penny,
        Nickel,
        Dime,
        Quarter,
    }

    fn value_in_cents(coin: Coin) -> u8 {
        match coin {
            Coin::Penny => 1,
            Coin::Nickel => 5,
            Coin::Dime => 10,
            Coin::Quarter => 25,
        }
    }

    //define a coin with a random value
    let coin = Coin::Quarter;

    //print the value of the coin
    println!("The value of the coin is: {}", value_in_cents(coin));
}
```

[![Control flow in Rust - Rust programming tutorial](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j47h1yuz70lxau2fg6v5.png)](https://youtu.be/2w_FTiD74JI)


## Repetition with Loops

Rust has three kinds of loops: loop, while, and for. Let’s cover each one with an example!

### Repeating Code with `loop`

The loop keyword tells Rust to execute a block of code repeatedly forever or until you explicitly tell it to stop.

```rust
fn main() {
    loop {
        print!("Hello, world!");
    }
}
```

This program will print again! over and over again forever or until you manually stop it (press Ctrl-C or send a SIGINT signal by typing ^C).


[![Control flow in Rust - Rust programming tutorial](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a9pe8jh8svuvsw5u3u9s.png)](https://youtu.be/2w_FTiD74JI)

### Returning Values from Loops

You can return a value from a loop by adding the value after the break expression you want to return. For example, we can return a value from a loop that prints the values from 1 to 4:

```rust
fn main() {
    let mut counter = 0;

    let result = loop {
        counter += 1;

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

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

The break expression will immediately stop a loop. So, if we break with no value, this expression will be equivalent to ().

In this case, the result will be 20, because the loop will stop when the counter is 10, and the value returned will be 10 * 2.

[![Control flow in Rust - Rust programming tutorial](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xoc2ci59dpiss5nb0b62.png)](https://youtu.be/2w_FTiD74JI)

### Conditional Loops with while

Another loop keyword in Rust is while. It behaves similarly to loop, except the condition goes before the loop block.

```rust
fn main() {
    let mut counter = 3;

    while counter != 0 {
        println!("{}", counter);

        counter -= 1;
        //wait for 1 second
        std::thread::sleep(std::time::Duration::from_secs(1));
    }

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

This program will print the numbers counting down from 3 to 1, and then it will print LIFTOFF!!!. If we forget to add number -= 1, the program will never exit the while loop because the condition will never be false.

[![Control flow in Rust - Rust programming tutorial](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m3ylerfmls5hp14mevef.png)](https://youtu.be/2w_FTiD74JI)

### Looping Through a Collection with for

The for loop is used to loop through each item in a collection. For example, if we wanted to loop through each item in an array of integers and print each item, we could use a for loop, like this:

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

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

the `.iter` method returns an iterator over the elements of the array.

This program will print each item in the array on its own line:

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

We can also use for to loop over the elements of a string that we’ve previously discussed:

```rust
fn main() {
    let s = "hello world";

    for c in s.chars() {
        println!("{}", c);
    }
}
```

This program will print each character in Hello World on its own line:

```bash
h
e
l
l
o

w
o
r
l
d
```

We can also use for with a range, like this:

```rust
fn main() {
    for number in 1..4 {
        println!("{}", number);
    }
    
    println!("go!!!");
}
```

This program will print the numbers counting down from 1 to 3, and then it will print `go!!!`

[![Control flow in Rust - Rust programming tutorial](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vt2czifkibjy0qvu73h2.png)](https://youtu.be/2w_FTiD74JI)

## Exercise - FizzBuzz problem

Last example is the FizzBuzz problem. 

The FizzBuzz problem is a classic programming problem often used as an interview question. The task is to print the numbers from 1 to 100. But for multiples of three, print "Fizz" instead of the number, and for the multiples of five, print "Buzz". For numbers which are multiples of both three and five, print "FizzBuzz".

Here's a simple implementation in Rust:

```rust
fn main() {
    for number in 1..=100 {
        if number % 3 == 0 && number % 5 == 0 {
            println!("FizzBuzz");
        } else if number % 3 == 0 {
            println!("Fizz");
        } else if number % 5 == 0 {
            println!("Buzz");
        } else {
            println!("{}", number);
        }
    }
}
```

The last 4 outputs should be:

```bash
97
98
Fizz
Buzz
```

[![Control flow in Rust - Rust programming tutorial](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0k32jh7qlevmpyqtrvab.png)](https://youtu.be/2w_FTiD74JI)

## Summary

That’s all there is to control flow in Rust! You can now write useful programs that do different things based on different conditions and repeat code while a condition holds true.

Here is the code with all the examples:

```rust
fn main() {
    //Basic if else
    let number = 3;

    if number < 5 {
        println!("condition was true");
    } else {
        println!("condition was false");
    }

    //let with if else
    let condition = true;
    let number = if condition {
        5
    } else {
        6
    };

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

    //Nested if expressions
    let num = 15;

    if num % 2 == 0 {
        println!("{} is even", num);
    } else {
        println!("{} is odd", num);

        if num > 10 {
            println!("{} is also greater than 10", num);
        } else {
            println!("{} is not greater than 10", num);
        }
    }
    println!("-------------------------------------------");


    //&& and || operators
    let a = 10;
    let b = 5;
    let c = 20;

    // Using && (AND) to check if 'a' is greater than 'b' AND 'b' is greater than 'c'
    if a > b && b > c {
        println!("a is greater than b and b is greater than c");
    } else {
        println!("Condition with && not met");
    }

    // Using || (OR) to check if 'a' is less than 'b' OR 'b' is less than 'c'
    if a > b || b > c {
        println!("At least one condition with || is met");
    } else {
        println!("Neither condition with || is met");
    }
    println!("-------------------------------------------");

    //Match statement
    enum Coin {
        Penny,
        Nickel,
        Dime,
        Quarter,
    }

    fn value_in_cents(coin: Coin) -> u8 {
        match coin {
            Coin::Penny => 1,
            Coin::Nickel => 5,
            Coin::Dime => 10,
            Coin::Quarter => 25,
        }
    }

    let coin = Coin::Quarter;
    println!("The value of the coin is: {}", value_in_cents(coin));
    println!("-------------------------------------------");

    //Infinite loop (commented out)
    // loop {
    //     println!("again!");
    // }

    // Returning a value from a loop
    let mut counter = 0;

    let result = loop {
        counter += 1;

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

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


    //While loop
    let mut counter = 3;

    while counter != 0 {
        println!("{}", counter);

        counter -= 1;
        //wait for 1 second
        std::thread::sleep(std::time::Duration::from_secs(1));
    }

    println!("LIFTOFF!!!");
    println!("-------------------------------------------");

    //For loop to iterate over a collection
    let a = [10, 20, 30, 40, 50];

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

    //For loop for elements in a string
    let s = "hello world";

    for c in s.chars() {
        println!("{}", c);
    }
    println!("-------------------------------------------");

    //For loop for elements in a range
    for number in (1..4).rev() {
        println!("{}!", number);
    }
    println!("LIFTOFF!!!");
    println!("-------------------------------------------");

    //FizzBuzz game
    for number in 1..=100 {
        if number % 3 == 0 && number % 5 == 0 {
            println!("FizzBuzz");
        } else if number % 3 == 0 {
            println!("Fizz");
        } else if number % 5 == 0 {
            println!("Buzz");
        } else {
            println!("{}", number);
        }
    }
    println!("-------------------------------------------");
}
```

Conclusions

In this lesson, we've covered the basic control flow in Rust. We've learned about if expressions, match, loop expressions, while expressions, and for expressions. We've also practiced with a simple exercise.

If you prefer a video version
{% youtube 2w_FTiD74JI %}

<!-- <iframe width="905" height="510" src="https://www.youtube.com/embed/2w_FTiD74JI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe> -->
    
A recap is available on [GitHub](https://youtu.be/2w_FTiD74JI) (link available in the video description)