Loops and Arrays in Rust

About This Module

This module covers Rust's loop constructs (for, while, loop) and array data structures. Understanding loops and arrays is essential for processing collections of data and implementing algorithms in Rust.

Prework

Prework Readings

Read the following sections from "The Rust Programming Language" book:

Pre-lecture Reflections

Before class, consider these questions:

  1. What are the different types of loops and when would you use each?
  2. How do arrays differ from more flexible data structures like vectors?
  3. What are the advantages of fixed-size arrays?
  4. How do ranges work in iteration and what are their bounds?
  5. When might you need labeled breaks and continues in nested loops?

Learning Objectives

By the end of this module, you should be able to:

  • Use for loops with ranges and collections
  • Work with while loops for conditional iteration
  • Understand loop for infinite loops with explicit breaks
  • Create and manipulate arrays in Rust
  • Use break and continue statements effectively
  • Apply loop labels for complex control flow
  • Understand array properties and limitations

For Loops and Ranges

Loops: for

Usage: loop over a range or collection

A range is (start..end), e.g. (1..5), where the index will vary as

Unless you use the notation (start..=end), in which case the index will vary as

#![allow(unused)]
fn main() {
// parentheses on the range are optional unless calling a method e.g. `.rev()`
// on the range
for i in 1..5 {
    println!("{}",i);
}
}
#![allow(unused)]
fn main() {
// inclusive range
for i in 1..=5 {
    println!("{}",i);
}
}
#![allow(unused)]
fn main() {
// reverse order. we need parentheses!
for i in (1..5).rev() {
    println!("{}",i)
}
}
#![allow(unused)]
fn main() {
// every other element 
for i in (1..5).step_by(2) {
    println!("{}",i);
}
}
#![allow(unused)]
fn main() {
println!("And now for the reverse");
for i in (1..5).step_by(2).rev() {
    println!("{}",i)
}
}
#![allow(unused)]
fn main() {
println!("But....");
for i in (1..5).rev().step_by(2) {
    println!("{}",i);
}
}

Arrays and for over an array

  • Arrays in Rust are of fixed length (we'll learn about more flexible Vec later)
  • All elements of the same type
  • You can not add or remove elements from an array (but you can change its value)
  • Python does not have arrays natively.

What's the closest thing in native python?

#![allow(unused)]
fn main() {
// simplest definition
// compiler guessing element type to be i32
// indexing starts at 0
let mut arr = [1,7,2,5,2];
arr[1] = 13;
println!("{} {}",arr[0],arr[1]);
}
#![allow(unused)]
fn main() {
let mut arr = [1,7,2,5,2];
// array supports sorting
arr.sort();

// loop over the array
for x in arr {
    println!("{}",x);
}
}
#![allow(unused)]
fn main() {
// create array of given length
// and fill it with a specific value
let arr2 = [15;3];
for x in arr2 {
    print!("{} ",x);  // notice print! instead of println!
}
}
#![allow(unused)]
fn main() {
// with type definition and shorthand to repeat values
let arr3 : [u8;3] = [15;3];

for x in arr3 {
    print!("{} ",x);
}
println!();

println!("arr3[2] is {}", arr3[2]);
}
#![allow(unused)]
fn main() {
let arr3 : [u8;3] = [15;3];
// get the length
println!("{}",arr3.len())
}

Loops: while

#![allow(unused)]
fn main() {
let mut number = 3;

while number != 0 {
    println!("{number}!");
    number -= 1;
}
println!("LIFT OFF!!!");

}

Infinite loop: loop

loop {
    // DO SOMETHING HERE
}

Need to use break to jump out of the loop!

#![allow(unused)]
fn main() {
let mut x = 1;
loop {
    if (x + 1) * (x + 1) >= 250 {break;}
    x += 1;
}
println!("{}",x)
}
  • loop can return a value!
  • break can act like return
#![allow(unused)]
fn main() {
let mut x = 1;
let y = loop {
    if x * x >= 250 {break x - 1;}
    x += 1;
};
println!("{}",y)
}
  • continue to skip the rest of the loop body and start the next iteration
#![allow(unused)]
fn main() {
// loop keyword similar to while (True) in Python
// break and continue keywords behave as you would expect
let mut x = 1;

let result = loop {  // you can capture a return value
    if x == 5 {
        x = x+1;
        continue;    // skip the rest of this loop body and start the next iteration
    }
    println!("X is {}", x);
    x = x + 1;
    if x==10 {
        break x*2;   // break with a return value
    }
};

println!("Result is {}", result);
}

Advanced break and continue

  • work in all loops
  • break: terminate the execution
    • can return a value in loop
  • continue: terminate this iteration and jump to the next one
    • in while, the condition will be checked
    • in for, there may be no next iteration
    • break and continue can use labels
#![allow(unused)]
fn main() {
for i in 1..=10 {
    if i % 3 != 0 {continue;}
    println!("{}",i);
};
}

You can also label loops to target with continue and break.

#![allow(unused)]
fn main() {
let mut x = 1;
'outer_loop: loop {
    println!("Hi outer loop");
    'inner_loop: loop {
        println!("Hi inner loop");
        x = x + 1;
        if x % 3 != 0 {
            continue 'outer_loop;  // skip the rest of the outer loop body and start the next iteration
        }
        println!("In the middle");
        if x >= 10 {
            break 'outer_loop;  // break the outer loop
        }
        println!("X is {}", x);
    }
    println!("In the end");
};

println!("Managed to escape! :-) with x {}", x);
}
#![allow(unused)]
fn main() {
let mut x = 1;
'outer_loop: loop {
    println!("Hi outer loop");
    'inner_loop: loop {
        println!("Hi inner loop");
        x = x + 1;
        if x % 3 != 0 {
            break 'inner_loop;  // break the inner loop, continue the outer loop
        }
        println!("In the middle");
        if x >= 10 {
            break 'outer_loop;  // break the outer loop
        }
        println!("X is {}", x);
    }
    println!("In the end");
};
println!("Managed to escape! :-) with x {}", x);
}
#![allow(unused)]
fn main() {
let x = 'outer_loop: loop {
    loop { break 'outer_loop 1234;}
};
println!("{}",x);
}

Loop Selection Guidelines

When to Use Each Loop Type:

For Loops:

  • Known range: Iterating over ranges or collections
  • Collection processing: Working with arrays, vectors, etc.
  • Counter-based iteration: When you need an index

While Loops:

  • Condition-based: Continue until some condition changes
  • Unknown iteration count: Don't know how many times to loop
  • Input validation: Keep asking until valid input

Loop (Infinite):

  • Event loops: Server applications, game loops
  • Breaking on complex conditions: When simple while condition isn't sufficient
  • Returning values: When loop needs to compute and return a result

Exercise

Here's an exam question from a previous semester. Analyze the code without any assistance to practice your skills for the next exam.

You are given the following Rust code

let mut x = 1;
'outer_loop: loop {
    'inner_loop: loop {
        x = x + 1;
        if x % 4 != 0 {
            continue 'outer_loop;
        }
        if x > 11 {
            break 'outer_loop;
        }
    }
};
println!("Managed to escape! :-) with x {}", x);

What is the value of x printed by the println! statement at the end?

Explain your answer.