Beginner · Types, control flow and functions · topic 8 of 50 · 25 min
Control flow: if, loop, while and for
Explanation
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.
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");
}
}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.
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 typesloop: 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.
let mut attempts = 0;
let result = loop {
attempts += 1;
if attempts == 3 {
break attempts * 10;
}
};
println!("{result}"); // 30while: repeat while a condition holds
let mut seats = 3;
while seats > 0 {
println!("{seats} seats left");
seats -= 1;
}
println!("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.
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}");
}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.
'outer: for row in 1..=3 {
for col in 1..=3 {
if row * col == 4 {
break 'outer;
}
print!("{} ", row * col);
}
}
// prints: 1 2 3 2Skipping 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.
for n in 1..=10 {
if n % 2 == 0 {
continue; // skip even numbers
}
print!("{n} "); // 1 3 5 7 9
}Which loop should I use?
| Situation | Best choice | Why |
|---|---|---|
| Go over every item of a list or a range | for | Cannot go past the end; no index bugs |
| Repeat while something is true, count unknown | while | The condition is checked before every round |
| Retry until success, and get a value out | loop with break value | Clear 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
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.
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" });
}Practice (0/3 done)
How many numbers does this print? for i in 0..5 { println!("{i}"); }
What does this print? let mut n = 1; let x = loop { n *= 2; if n > 10 { break n; } }; println!("{x}");
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
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Mini project: reading input from the userTypes, control flow and functions · same module
- Compound types: tuples and arraysTypes, control flow and functions · same module
- Loops and rangesKotlin and Android App Development · Kotlin basics
- Loops: for, while, do-while and range-forC++ Programming (modern C++ and DSA) · Decisions, loops and functions
- Loops: repeating workFrontend Web Development · JavaScript basics
- Loops: for, while, do-while and for-eachJava Programming (Core to Spring Boot) · Control flow and methods
Questions people ask about this
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
What does break do inside a loop?Related
Answer: Exits the loop immediately
break leaves the innermost loop (or switch) at once.
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.
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.
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 more topic in “Types, control flow and functions” before its exam: Mini project: reading input from the user.
- Module 2 exam: Types, control flow and functions · 13 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Ownership: Rust's big idea. 50 topics left in the course before the final exam.