Beginner Level

Control Flow

Chapter 4: Control Flow šŸ”„

Control flow is how you make decisions and repeat actions in your programs. Rust provides several constructs for controlling the flow of execution.

If Expressions

Basic If

fn main() {
    let number = 3;

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

If-Else If

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");
    }
}

If in a Let Statement

Since if is an expression, you can use it on the right side of a let statement:

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

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

Loops

Loop - Infinite Loop

fn main() {
    let mut counter = 0;

    let result = loop {
        counter += 1;

        if counter == 10 {
            break counter * 2;  // Return value from loop
        }
    };

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

While Loop

fn main() {
    let mut number = 3;

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

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

For Loop

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

    for element in a {
        println!("the value is: {}", element);
    }
    
    // Using ranges
    for number in 1..4 {
        println!("{}!", number);
    }
    
    // Inclusive range
    for number in 1..=3 {
        println!("{}!", number);
    }
    
    // Reverse countdown
    for number in (1..4).rev() {
        println!("{}!", number);
    }
}

Match Expression

Basic Match

fn main() {
    let x = 1;

    match x {
        1 => println!("one"),
        2 => println!("two"),
        3 => println!("three"),
        _ => println!("anything"),
    }
}

Match with Values

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

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter,
}

Match Guards

fn main() {
    let num = Some(4);

    match num {
        Some(x) if x < 5 => println!("less than five: {}", x),
        Some(x) => println!("{}", x),
        None => (),
    }
}

If Let

For when you only care about one pattern:

fn main() {
    let some_u8_value = Some(0u8);
    
    // Instead of this verbose match:
    match some_u8_value {
        Some(3) => println!("three"),
        _ => (),
    }
    
    // Use if let:
    if let Some(3) = some_u8_value {
        println!("three");
    }
}

Practical Examples

Example 1: Grade Calculator

fn get_letter_grade(score: u32) -> char {
    match score {
        90..=100 => 'A',
        80..=89 => 'B',
        70..=79 => 'C',
        60..=69 => 'D',
        _ => 'F',
    }
}

fn main() {
    let scores = [95, 87, 76, 65, 45];
    
    for score in scores {
        let grade = get_letter_grade(score);
        println!("Score: {} -> Grade: {}", score, grade);
    }
}

Example 2: Number Guessing Game Logic

use std::cmp::Ordering;

fn check_guess(guess: u32, secret: u32) -> String {
    match guess.cmp(&secret) {
        Ordering::Less => "Too small!".to_string(),
        Ordering::Greater => "Too big!".to_string(),
        Ordering::Equal => "You win!".to_string(),
    }
}

fn main() {
    let secret_number = 42;
    let guesses = [25, 50, 42, 30];
    
    for guess in guesses {
        let result = check_guess(guess, secret_number);
        println!("Guess: {} -> {}", guess, result);
        
        if guess == secret_number {
            break;
        }
    }
}

Practice Exercises

Exercise 1: FizzBuzz

Write a program that prints numbers 1-100, but:

  • Print "Fizz" for multiples of 3
  • Print "Buzz" for multiples of 5
  • Print "FizzBuzz" for multiples of both

Exercise 2: Prime Number Checker

Write a function that checks if a number is prime:

fn is_prime(n: u32) -> bool {
    // Your implementation here
}

Exercise 3: Factorial Calculator

Write a function that calculates factorial using a loop:

fn factorial(n: u32) -> u32 {
    // Your implementation here
}

Loop Labels

For nested loops, you can use labels:

fn main() {
    'outer: loop {
        println!("Entered the outer loop");

        'inner: loop {
            println!("Entered the inner loop");
            break 'outer;
        }

        println!("This point will never be reached");
    }

    println!("Exited the outer loop");
}

Key Takeaways

  • āœ… if is an expression that can return values
  • āœ… loop creates infinite loops, while has conditions, for iterates
  • āœ… match is powerful pattern matching (exhaustive)
  • āœ… if let is syntactic sugar for simple matches
  • āœ… Use ranges (1..5, 1..=5) for numeric iterations
  • āœ… Loop labels help with nested loop control

Ready for Chapter 5? → Ownership and Borrowing

šŸ¦€ Rust Programming Tutorial

Learn from Zero to Advanced

Built with Next.js and Tailwind CSS • Open Source