DEV Community

Cover image for [Rust Guide] 3.6. Control Flow - Loops
SomeB1oody
SomeB1oody

Posted on

[Rust Guide] 3.6. Control Flow - Loops

3.6.0. Before the Main Content

Welcome to Chapter 3 of Rust self-study. There are 6 sections in total:

  • Variables and Mutability
  • Data Types: Scalar Types
  • Data Types: Compound Types
  • Functions and Comments
  • Control Flow: if else
  • Control Flow: Loops (this article)

Through the small game in Chapter 2 (strongly recommended for beginners who haven't read it), you should already understand the basic syntax of Rust. In Chapter 3, we will go deeper and learn general programming concepts in Rust.

If you like it, remember to like, bookmark, and follow. Follow the series if you want to keep learning.


3.6.1. Loops in Rust

Rust provides three types of loops:

  • loop
  • while
  • for

3.6.2. loop Loop

The loop keyword tells Rust to repeatedly execute a block of code until explicitly stopped.

fn main(){
    loop {
        println!("6657 up up!");
    }
}
Enter fullscreen mode Exit fullscreen mode

You can use the break keyword to stop a loop:

fn main(){
    let mut counter = 0;
    let result = loop {
        counter += 1;

        if counter == 10 {
            break counter * 2;
        }
    };
    println!("The result is:{}", result);
}
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • counter starts at 0 and increments by 1 in each iteration.
  • When counter == 10, break exits the loop and returns counter * 2 (which is 20).
  • loop is an expression, and its return value is the value passed to break, so it can be assigned directly to result.
  • The final output is 20.

Key points:

  • loop in Rust is an expression and can return a value.
  • break can carry a return value.
  • Since let statements require a semicolon after the assigned expression, the closing } of the loop must be followed by ;.

3.6.3. while Conditional Loop

A while loop checks the condition before each iteration.

fn main() {
    let mut countdown = 10; // countdown starts from 10

    println!("Rocket Launch Countdown:");

    while countdown > 0 {
        println!("T-minus {}...", countdown);
        countdown -= 1; // decrease by 1 each time
    }

    println!("🚀 Liftoff!");
    println!("Houston, we have a problem.");
}
Enter fullscreen mode Exit fullscreen mode

Output:

Rocket Launch Countdown:
T-minus 10...
T-minus 9...
T-minus 8...
T-minus 7...
T-minus 6...
T-minus 5...
T-minus 4...
T-minus 3...
T-minus 2...
T-minus 1...
🚀 Liftoff!
Houston, we have a problem.
Enter fullscreen mode Exit fullscreen mode

3.6.4. Iterating Over Collections with for

Although while and loop can be used to iterate over collections, they are error-prone and less efficient.

Example using while:

fn main() {
    let numbers = [10, 20, 30, 40, 50];
    let mut index = 0;

    println!("Using while loop:");
    while index < 5 {
        println!("Number at index {}: {}", index, numbers[index]);
        index += 1;
    }
}
Enter fullscreen mode Exit fullscreen mode

Using while can easily lead to index out-of-bounds errors (panic!), and it is less efficient due to repeated condition checks.

Equivalent example using for:

fn main() {
    let numbers = [10, 20, 30, 40, 50];

    println!("Using for loop:");
    for (index, number) in numbers.iter().enumerate() {
        println!("Number at index {}: {}", index, number);
    }
}
Enter fullscreen mode Exit fullscreen mode

1. numbers.iter()

  • Calls .iter() on the collection numbers, creating an immutable iterator that accesses elements one by one.
  • In Rust, for loops operate on iterators rather than directly on collections.
  • .iter() is commonly used for vectors and other collections, producing references to elements.
  • for loops are concise and execute code for each element efficiently and safely.

2. .enumerate()

  • Attaches an index to each element in the iterator.
  • The index starts from 0 and is of type usize.
  • It transforms each element into (index, value):
    • index: position in the collection
    • value: reference to the element
  • Returns a new iterator of type (usize, &T).

3. for (index, number) in ...

  • Rust for loops support tuple destructuring.
  • (index, number) directly unpacks (usize, &T) into:
    • index: index of the element
    • number: reference to the element

Example execution with [10, 20, 30, 40, 50]:

  1. numbers.iter() creates an iterator
  2. .enumerate() produces (index, &value)
  3. Each loop iteration destructures:
    • First: index = 0, number = &10
    • Second: index = 1, number = &20
    • Third: index = 2, number = &30
    • ...
  4. Prints each index and value

Because of its safety and simplicity, for is the most commonly used loop in Rust.


3.6.5. Range

Range is provided by the standard library. It can generate sequences of numbers (excluding the end by default). The rev method reverses a range.

fn main() {
    println!("Rocket Launch Countdown:");

    for countdown in (1..=10).rev() {
        println!("T-minus {}...", countdown);
    }

    println!("🚀 Liftoff!");
    println!("Houston, we have a problem.");
}
Enter fullscreen mode Exit fullscreen mode

This example uses for, Range, and rev to implement the same countdown as the previous while example.

Code Explanation

  1. (1..=10):

    • A Range from 1 to 10 (inclusive)
    • ..= means the upper bound is included
  2. .rev():

    • Reverses the iterator to produce a descending sequence from 10 to 1

Top comments (0)