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:
- Chapter 3.5: Control Flow - Focus on loops
- Chapter 4.1: What Is Ownership? - Arrays and ownership
- Chapter 8.1: Storing Lists of Values with Vectors - Introduction only
Pre-lecture Reflections
Before class, consider these questions:
- What are the different types of loops and when would you use each?
- How do arrays differ from more flexible data structures like vectors?
- What are the advantages of fixed-size arrays?
- How do ranges work in iteration and what are their bounds?
- 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
forloops with ranges and collections - Work with
whileloops for conditional iteration - Understand
loopfor infinite loops with explicit breaks - Create and manipulate arrays in Rust
- Use
breakandcontinuestatements 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
Veclater) - 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) }
loopcan return a value!breakcan act likereturn
#![allow(unused)] fn main() { let mut x = 1; let y = loop { if x * x >= 250 {break x - 1;} x += 1; }; println!("{}",y) }
continueto 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
- can return a value in
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 breakandcontinuecan use labels
- in
#![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.