Control Flow in Rust

In this lesson, we'll explore how Rust handles program flow control through conditionals, loops, and pattern matching. These are essential tools for writing programs that can make decisions and repeat actions.

If Expressions

In Rust, if is an expression, which means it can return a value:

fn main() {
    let number = 7;

    // Basic if-else
    if number < 5 {
        println!("number is less than 5");
    } else if number > 5 {
        println!("number is greater than 5");
    } else {
        println!("number is 5");
    }

    // If in a let statement
    let condition = true;
    let result = if condition {
        "condition was true"
    } else {
        "condition was false"
    };
    println!("Result: {}", result);
}

Loops

Rust provides several ways to repeat code:

Loop

The loop keyword creates an infinite loop that you can break out of:

fn main() {
    let mut counter = 0;

    let result = loop {
        counter += 1;

        if counter == 10 {
            break counter * 2; // Returns a value
        }
    };

    println!("The result is {}", result); // Prints: The result is 20
}

While Loop

For conditional looping:

fn main() {
    let mut number = 3;

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

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

For Loop

For iterating over collections:

fn main() {
    // Iterating over a range
    for number in 1..=5 {
        println!("{}!", number);
    }

    // Iterating over an array
    let colors = ["red", "green", "blue"];
    for color in colors.iter() {
        println!("Color: {}", color);
    }
}

Pattern Matching

One of Rust's most powerful features is pattern matching with match:

fn main() {
    let number = 13;

    match number {
        // Match a single value
        1 => println!("One!"),
        // Match several values
        2 | 3 | 5 | 7 | 11 | 13 => println!("This is a prime number!"),
        // Match a range
        14..=19 => println!("A teen"),
        // Handle the rest of cases
        _ => println!("Not a special number"),
    }
}

If Let

For simpler pattern matching:

fn main() {
    let some_value = Some(3);
    
    // Instead of:
    match some_value {
        Some(3) => println!("three"),
        _ => (),
    }

    // You can write:
    if let Some(3) = some_value {
        println!("three");
    }
}

Practice Exercises

Try these exercises in the playground:

  1. Create a program that uses a loop to find the first 5 numbers divisible by both 3 and 5
  2. Write a function that uses pattern matching to convert numbers 1-5 to their text representation
  3. Use a for loop to calculate the sum of all numbers from 1 to 100
  4. Create a nested if-else structure and then refactor it to use match instead

Remember: Rust's control flow features are expressions, meaning they can return values. This leads to more concise and expressive code!