Start learning free

LESSON 160 OF 414 · LOOPING OVER ARRAY INDICES

Break In For Loops in Rust

Lesson Read the full explanation

With the break statement, we can prematurely terminate a loop from inside that loop.

When Rust reaches the break statement, it's going to immediately terminate the loop without checking any conditions.


Breaking a for loop:

In this example, we will terminate the loop when we find a "banana" in our vector:

let fruits = vec!["kivi", "orange", "banana", "apple", "pear"];
for fruit in &fruits {
	println!("{}", fruit);
	if *fruit == "banana" {
		break;
	}
}

The output of this code is:

kivi
orange
banana

As you can see, our program doesn't print apple and pear.

Here's what happens during this loop:

1. First iteration:
	a. fruit = "kivi"
	b. println!("{}", fruit); => Output: kivi
	c. Is *fruit == "banana"? No.

2. Second iteration:
	a. fruit = "orange"
	b. println!("{}", fruit); => Output: orange
	c. Is *fruit == "banana"? No.

3. Third iteration:
	a. fruit = "banana"
	b. println!("{}", fruit); => Output: banana
	c. Is *fruit == "banana"? Yes:
          break => Exit the loop immediately

Here's the same program but iterating through the vector with indices instead:

let fruits = vec!["kivi", "orange", "banana", "apple", "pear"];
for i in 0..fruits.len() {
	println!("Index {}: {}", i, fruits[i]);
	if fruits[i] == "banana" {
		break;
	}
}

The output of this code is:

Index 0: kivi
Index 1: orange
Index 2: banana

As you can see, our program doesn't print apple and pear.


Assignment
Let's print all the lessons our student finished!


Hint
Look at the examples above if you get stuck.


STEP 1 OF 3
    Ctrl + Enter to check

    RUST · LOOPING OVER ARRAY INDICES

    Break In For Loops in Rust, explained

    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, break leaves 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 write break 'outer; to leave the outer loop from inside the inner one.
    • A loop that never matches. If the condition is never true, break never 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 with break value;. A for loop can't: its break carries no value.
    • Moving versus borrowing. for fruit in &fruits borrows the vector, so fruits is still usable afterwards. for fruit in fruits moves the vector into the loop, and any later use of fruits is a compile error: "borrow of moved value". After a break the 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.

    1. 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.
    2. Print the lesson with println!("Finished {}", lesson);. The {} is filled with the argument.
    3. 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

    • break ends 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 break affects only the innermost loop, unless you use a label.
    • Looping by value moves the vector; looping over &vector borrows it.
    Keep going with RustAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free