OSRust.005: Control Flow — if, loop, while, for, break, and continue

Original neon-green and amber industrial rail-yard illustration representing Rust branching, loops, break, continue, and repeated execution paths.

Elementary Overview

Control flow decides which code runs, how many times it runs, and when execution leaves a repeated block. Rust provides if expressions for decisions and three primary loop forms: loop, while, and for. Rust also makes several of these constructs expressions, so they can produce values rather than merely controlling execution.

This lesson follows OSRust.004: Functions, Parameters, Expressions, and Return Values. That lesson established Rust’s expression-oriented model. Control flow extends that model: an if block can produce a value, and a loop can return a value through break.

Francesco Ciulla walks through Rust if expressions, loop, while, for, and basic control-flow exercises.

Learning Objectives

  • Use if, else if, and else.
  • Explain why Rust requires an if condition to evaluate to bool.
  • Use an if expression to assign a value.
  • Create unconditional repetition with loop.
  • Return a value from loop using break value.
  • Repeat while a Boolean condition is true with while.
  • Iterate safely through collections and ranges with for.
  • Skip an iteration with continue.
  • Exit nested loops using labels.
  • Choose the clearest loop form for a given problem.

if Is an Expression

Rust begins a conditional branch with if. The condition must evaluate to a Boolean value. Rust does not automatically reinterpret integers such as 0 or 1 as false or true, so comparisons must be explicit.

fn main() {
    let temperature = 78;

    if temperature > 85 {
        println!("Cooling alert");
    } else if temperature > 75 {
        println!("Warm");
    } else {
        println!("Normal");
    }
}

The first true branch runs and the remaining branches are skipped. Conditions can combine comparisons with Boolean operators such as &&, ||, and !.

Assigning a Value with if

Because if is an expression, its result can be assigned directly to a variable. Every branch that can produce the result must have a compatible type.

fn main() {
    let online = true;

    let status = if online {
        "running"
    } else {
        "offline"
    };

    println!("{status}");
}

If one branch returned a string slice and the other returned an integer, the compiler would reject the assignment because one expression cannot have two incompatible result types. This builds directly on the type system introduced in OSRust.003: Scalar and Compound Data Types.

A focused Rust tutorial demonstrates if, loop, while, and for control flow.

Unconditional Repetition with loop

The loop keyword repeats a block indefinitely until execution reaches a break, a function returns, the process exits, or another diverging operation occurs. It communicates intentional indefinite repetition more clearly than writing an artificial always-true condition.

fn main() {
    let mut attempts = 0;

    loop {
        attempts += 1;
        println!("Attempt {attempts}");

        if attempts == 3 {
            break;
        }
    }
}

Returning a Value from loop

Rust’s loop is an expression and can return a value. Supply that value after break, then assign the loop expression to a variable.

fn main() {
    let mut counter = 0;

    let result = loop {
        counter += 1;

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

    println!("{result}");
}

This prints 20. The value after break becomes the value of the entire loop expression. That pattern is useful when repetition searches for, computes, or waits for a value before continuing.

Rust developers discuss the useful combination of loop, break values, match, and continue in real programs.

Conditional Repetition with while

A while loop repeats only while its condition evaluates to true. It is appropriate when the number of iterations is not fixed in advance but the continuation condition is easy to state.

fn main() {
    let mut countdown = 3;

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

    println!("LIFTOFF");
}

Compared with manually combining loop, if, and break, while makes the controlling condition visible at the top of the loop.

Iterating with for

for is usually the clearest choice for traversing a collection or known range. It avoids manual indexing and lets Rust’s iterator system drive each iteration.

fn main() {
    let temperatures = [68, 71, 74, 79];

    for reading in temperatures {
        println!("{reading} F");
    }
}

This approach is safer and clearer than maintaining a separate integer index for a simple traversal. The loop receives each item from the collection in sequence.

Ranges

Ranges work naturally with for. The expression 1..5 produces 1 through 4, while 1..=5 includes 5.

fn main() {
    for rack in 1..=5 {
        println!("Checking rack {rack}");
    }

    for number in (1..=3).rev() {
        println!("{number}!");
    }
}
Code of the Future demonstrates Rust conditions, while loops, for ranges, and collection iteration.

Skipping Work with continue

continue immediately ends the current iteration and returns control to the loop head. In a for loop, iteration proceeds to the next item.

fn main() {
    for port in 1..=8 {
        if port == 4 {
            continue;
        }

        println!("Testing port {port}");
    }
}

Port 4 is skipped, while the remaining ports continue normally. Use continue when the current item should be ignored without terminating the entire loop.

Breaking and Continuing Nested Loops with Labels

By default, break and continue affect the innermost enclosing loop. Rust lets you label loops with a leading apostrophe so nested control flow can target a specific outer loop.

fn main() {
    ‘rack_scan: for rack in 1..=3 {
        for port in 1..=4 {
            println!(“rack {rack}, port {port}”);

            if rack == 2 && port == 3 {
                break ‘rack_scan;
            }
        }
    }
}

The labeled break exits the outer rack_scan loop immediately. A labeled continue can similarly skip directly to the next iteration of a selected outer loop.

Choosing the Right Loop

  • Use for when iterating through a collection, iterator, or known range.
  • Use while when repetition is governed by a Boolean condition.
  • Use loop when repetition is intentionally open-ended and exit conditions occur inside the body.
  • Use break value when a loop is computing or searching for a value.
  • Use continue when one iteration should be skipped but repetition should continue.
  • Use labels sparingly when nested loops require explicit control of an outer loop.

Mini Lab

  1. Create a project with cargo new control_flow_lab.
  2. Use an if expression to classify a temperature as "normal", "warm", or "hot".
  3. Use loop with break value to calculate a result after five iterations.
  4. Create a countdown with while.
  5. Create an array of five device names and iterate through it with for.
  6. Use a range from 1 through 10 and skip even values with continue.
  7. Create nested rack-and-port loops and exit the outer loop with a label when a target rack and port are found.
  8. Run cargo fmt, cargo check, and cargo run.

Knowledge Check

  1. What type must an if condition evaluate to?
  2. Can an if expression produce a value?
  3. What does loop do by default?
  4. How can a loop return a value?
  5. When is while appropriate?
  6. Why is for usually preferable to manual indexing for simple collection traversal?
  7. What does continue do?
  8. Which loop does an unlabeled break exit?
  9. What problem do loop labels solve?

Answers

  1. bool.
  2. Yes. All result-producing branches must have compatible types.
  3. It repeats indefinitely.
  4. Use break value and assign the loop expression.
  5. When repetition should continue while a Boolean condition remains true.
  6. It expresses iteration directly and avoids unnecessary manual index management.
  7. It skips the remainder of the current iteration and starts the next one.
  8. The innermost enclosing loop.
  9. They let break or continue target a specific loop in nested control flow.

Previous Related Lessons

Primary References

Elementary Conclusion

Rust control flow is structured around explicit Boolean decisions and expressive loops. Use if to choose a path, for to traverse data, while to repeat under a condition, and loop when exit logic belongs inside the body. Once break, continue, values, ranges, and labels are understood, these constructs become the foundation for larger Rust programs.

BitcoinVersus.Tech Editor’s Note:
We volunteer daily to ensure the credibility of the information on this platform is Verifiably True. If you would like to support to help further secure the integrity of our research initiatives, please donate using the QR code provided

Bitcoin donation QR code for 5,000 sats.

For best QR-code scanning results, please scan this donation code from a desktop or larger screen. Mobile screens may prevent camera recognition.

Leave a Reply