What break does
A for loop normally runs until it has visited every item. The break statement ends it early. When Rust reaches break, the loop stops immediately, and the program continues with the first statement after the loop. Use it when the work is finished before the items run out, for example when you have found what you were looking for.
Breaking out of a loop over elements
This loop prints fruits until it prints a banana:
let fruits = vec!["kivi", "orange", "banana", "apple", "pear"];
for fruit in &fruits {
println!("{}", fruit);
if *fruit == "banana" {
break;
}
}
The output:
kivi
orange
banana
The third iteration prints banana first, then the if is true and break runs. The loop never visits apple or pear. Because the print comes before the check, the matching item is still printed. If you put the if first, the banana would be skipped.
Looping over &fruits gives fruit as a reference, a &&str here, which is why the comparison dereferences it with *fruit.
Breaking out of a loop over indices
The same program with an index loop:
let fruits = vec!["kivi", "orange", "banana", "apple", "pear"];
for i in 0..fruits.len() {
println!("Index {}: {}", i, fruits[i]);
if fruits[i] == "banana" {
break;
}
}
Index 0: kivi
Index 1: orange
Index 2: banana
Here fruits[i] is a plain &str, so no dereference is needed. The index loop is handy when the position matters, such as recording where the match happened.
Good to know
- Only the innermost loop. In nested loops,
breakleaves just the loop it is written in. The outer loop continues. Rust also lets you name a loop with a label such as'outer:and writebreak 'outer;to leave the outer loop from inside the inner one. - A loop that never matches. If the condition is never true,
breaknever runs and the loop visits every item, so with no banana the whole list prints. - Breaking with a value. The plain
loop { }form can hand a value back withbreak value;. Aforloop can't: itsbreakcarries no value. - Moving versus borrowing.
for fruit in &fruitsborrows the vector, sofruitsis still usable afterwards.for fruit in fruitsmoves the vector into the loop, and any later use offruitsis a compile error: "borrow of moved value". After abreakthe loop is over, but the vector has already been moved.
The exercise
The starter code defines a vector of lessons and the last one the student finished:
let lessons = vec!["variables", "conditionals", "arrays", "functions", "loops"];
let last_finished_lesson = "functions";
The task is to print every lesson the student finished, up to and including last_finished_lesson.
- Loop over the lessons. Write
for lesson in lessons. Each item is a&str, so you get the lesson directly and don't need an index. - Print the lesson with
println!("Finished {}", lesson);. The{}is filled with the argument. - Stop at the last finished lesson. After the print, add
if lesson == last_finished_lesson { break; }. Both sides are&str, so they compare by content. The check comes after the print so the last finished lesson is still shown.
let lessons = vec!["variables", "conditionals", "arrays", "functions", "loops"];
let last_finished_lesson = "functions";
for lesson in lessons {
println!("Finished {}", lesson);
if lesson == last_finished_lesson {
break;
}
}
The output:
Finished variables
Finished conditionals
Finished arrays
Finished functions
The lesson loops is never reached, because the loop ends right after functions.
Key takeaways
breakends the loop at once and the program continues after it.- Where you put the check decides whether the matching item is processed first or skipped.
- In nested loops
breakaffects only the innermost loop, unless you use a label. - Looping by value moves the vector; looping over
&vectorborrows it.
