Skip to content

Beginner · Types, control flow and functions · topic 8 of 50 · 25 min

Control flow: if, loop, while and for

Explanation

if needs a real bool; Rust has no "truthy" values. Because if is an expression, it can give a value: let fee = if member { 0 } else { 50 };. Rust has three loops: loop (forever, until break, which can return a value), while (while a condition is true) and for (over a range or a collection, the most used).

Decisions with if

Control flow decides which code runs and how many times. if runs a block only when a condition is true. In Rust, the condition must be a bool. You cannot write if count { ... } with a number like in C, Python or JavaScript; write if count != 0. This removes a whole class of bugs.

rust
fn main() {
    let age = 20;
    if age >= 18 {
        println!("Can vote");
    } else if age >= 16 {
        println!("Can get a learner's licence soon");
    } else {
        println!("Too young");
    }
}
No brackets around the condition, but the curly braces are always required.

if is an expression

Because if produces a value, you can use it on the right side of let. Both branches must give the same type.

rust
let is_member = true;
let delivery_fee = if is_member { 0 } else { 40 };
println!("Fee: {delivery_fee}");   // Fee: 0

// let x = if is_member { 0 } else { "free" };  // error: if and else have incompatible types
This replaces the ?: operator of other languages.

loop: repeat until break

loop repeats forever until you call break. You can also hand a value out of the loop: break value. This is handy for retrying something until it works.

rust
let mut attempts = 0;
let result = loop {
    attempts += 1;
    if attempts == 3 {
        break attempts * 10;
    }
};
println!("{result}");   // 30
break with a value ends the loop and makes that the loop's value.

while: repeat while a condition holds

rust
let mut seats = 3;
while seats > 0 {
    println!("{seats} seats left");
    seats -= 1;
}
println!("Sold out!");
Prints 3, 2 and 1 seats left, then Sold out!

for: the loop you will use most

for goes over each item of a collection or a range. A range is written start..end, which stops before end, or start..=end, which includes end. for loops cannot read past the end of a collection, so they are safer than counting with while.

rust
for i in 1..=5 {
    print!("{i} ");          // 1 2 3 4 5
}
println!();
for i in (1..4).rev() {
    print!("{i} ");          // 3 2 1
}
println!();
let cities = ["Delhi", "Chennai", "Kolkata"];
for city in cities {
    println!("Train to {city}");
}
.rev() walks a range backwards.

Loop labels

With nested loops, break and continue affect the innermost loop. To stop an outer loop, give it a label starting with an apostrophe and use break 'label.

rust
'outer: for row in 1..=3 {
    for col in 1..=3 {
        if row * col == 4 {
            break 'outer;
        }
        print!("{} ", row * col);
    }
}
// prints: 1 2 3 2
At row 2, col 2 the product is 4, so both loops stop.

Skipping a round with continue

continue jumps straight to the next round of the loop, skipping the rest of the body. It is useful for ignoring items you do not care about, such as blank lines in a file or cancelled orders in a list. Like break, it can take a label to skip a round of an outer loop.

rust
for n in 1..=10 {
    if n % 2 == 0 {
        continue;     // skip even numbers
    }
    print!("{n} ");   // 1 3 5 7 9
}
Only odd numbers reach the print! line.

Which loop should I use?

SituationBest choiceWhy
Go over every item of a list or a rangeforCannot go past the end; no index bugs
Repeat while something is true, count unknownwhileThe condition is checked before every round
Retry until success, and get a value outloop with break valueClear exit point that also returns the result

Most Rust code uses for. When you catch yourself writing a while loop with a counter variable that you increase by hand, a for loop over a range is usually shorter and safer.

Common mistakes

  • if x = 5 instead of if x == 5. Assignment is not a bool, so Rust refuses to compile, which is good.
  • Using 1..10 when you meant to include 10. Use 1..=10.
  • Different types in if/else branches used as a value. Make both branches give the same type.
  • An endless loop with no break. Every loop needs a way out.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Control flow: if, loop, while and for · 1/7

if / else if / else

Control flow decides what runs and how many times. First, if.

Prefer a video by a teacher? Find free videos on “rust control flow if loop while for range tutorial” on YouTube ↗

In real life: Retrying an OTP check

A banking app lets a user try an OTP at most 3 times. A for loop over 1..=3 gives exactly three tries, and the result of the check is stored with if as an expression. A loop with break value could also return which attempt succeeded.

rust
fn main() {
    let correct = 4821;
    let typed = [1111, 4821, 9999];
    let mut ok = false;
    for attempt in 1..=3 {
        let guess = typed[attempt - 1];
        let status = if guess == correct { "ok" } else { "wrong" };
        println!("Attempt {attempt}: {status}");
        if guess == correct {
            ok = true;
            break;
        }
    }
    println!("{}", if ok { "Logged in" } else { "Locked" });
}
Attempt 1 is wrong, attempt 2 is ok, so it prints Logged in.

Practice (0/3 done)

Task 1 · Question

How many numbers does this print? for i in 0..5 { println!("{i}"); }

Task 2 · Question

What does this print? let mut n = 1; let x = loop { n *= 2; if n > 10 { break n; } }; println!("{x}");

Task 3 · Practice

Write FizzBuzz for 1 to 30 with a for loop, but use the words "Chai" (multiple of 3), "Samosa" (multiple of 5) and "ChaiSamosa" (both). Then write a while loop that halves 1000 until it is below 10 and prints each step.

Quick quiz

Question 1

1.let n = 3; Which line compiles?

Question 2

2.Which range includes 10?

Question 3

3.What is special about loop compared to while?

Question 4

4.What does let x = if true { 5 } else { "five" }; do?

Question 5

5.Which loop is safest for going over every item of an array?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

let n = 3; Which line compiles?

Answer: if n != 0 { }

The condition must be a bool, so compare explicitly.

Which range includes 10?

Answer: 1..=10

..= includes the end value.

What is special about loop compared to while?

Answer: It can return a value with break value

loop can hand a value out with break, which makes it an expression.

What does let x = if true { 5 } else { "five" }; do?

Answer: Compile error: incompatible types in the branches

Both branches must produce the same type.

Which loop is safest for going over every item of an array?

Answer: for item in array

for cannot go past the end, so there are no index mistakes.

Which loop always runs its body at least once?Related

Answer: do-while

do-while checks the condition after the body.

From Loops and ranges

What does break do inside a loop?Related

Answer: Exits the loop immediately

break leaves the innermost loop (or switch) at once.

From Loops: for, while, do-while and range-for

Which loop is best to visit every item of an array?Related

Answer: for...of

for...of gives you each item in turn, with no index to manage.

From Loops: repeating work

How do you leave an outer loop from inside an inner loop?Related

Answer: A labelled break, like break outer;

Labels let break target an outer loop.

From Loops: for, while, do-while and for-each

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 1 more topic in “Types, control flow and functions” before its exam: Mini project: reading input from the user.
  2. Module 2 exam: Types, control flow and functions · 13 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Ownership: Rust's big idea. 50 topics left in the course before the final exam.

← Previous: Functions, statements and expressions