Chapter 16: Rust For Loop
Rust for loops
The for loop is Rust’s most idiomatic and most frequently used loop (in real projects written in 2025–2026, for appears in ~60–80% of all loop situations). Why? Because Rust turns almost everything into an iterator, and for works beautifully with them — it’s safe, expressive, clean, and prevents many classic off-by-one or bounds errors that plague other languages.
Let me teach this like we’re sitting together in a café near Hi-Tech City: slowly, with tons of copy-paste examples you can run right now (cargo run), everyday Hyderabad analogies (traffic counting, biryani ingredients, weekdays), comparisons to other languages, and building from simple to advanced patterns.
1. Basic Syntax – The Classic Form
|
0 1 2 3 4 5 6 7 8 |
for VARIABLE in ITERATOR { // code that runs once per item } |
- VARIABLE — gets a new value each iteration (usually by value or reference)
- ITERATOR — anything that implements IntoIterator (ranges, arrays, Vec, strings, maps, custom types…)
- No parentheses needed around the condition
- No manual increment/decrement needed — the iterator handles it
Simplest example — counting with a range:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
fn main() { for i in 1..6 { // 1, 2, 3, 4, 5 (exclusive upper bound) println!("Count: {}", i); } println!("---"); for i in 1..=5 { // 1 to 5 inclusive (very common!) println!("Inclusive: {}", i); } } |
Output:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Count: 1 Count: 2 Count: 3 Count: 4 Count: 5 --- Inclusive: 1 Inclusive: 2 Inclusive: 3 Inclusive: 4 Inclusive: 5 |
Behind the scenes: 1..6 creates a Range<usize> struct. for calls .into_iter() on it → produces values one by one until empty.
2. Looping Over Arrays & Slices (Very Common)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
fn main() { let weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]; for day in weekdays { println!("Today is {} — time to code in Rust! 🦀", day); } // With index (super useful!) for (index, day) in weekdays.iter().enumerate() { println!("Day #{} → {}", index + 1, day); } } |
- weekdays → array implements IntoIterator → gives owned &str each time
- .iter() → gives &str references (borrow, no move)
- .enumerate() → pairs index + value (returns (usize, &T))
3. Looping Over Vec (Dynamic Lists)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
fn main() { let mut spice_levels = vec![3, 5, 7, 10]; // out of 10 for Hyderabadi biryani // Read-only for level in &spice_levels { println!("Spice: {} 🔥", level); } // Modify in place (mutable reference) for level in &mut spice_levels { *level += 1; // make it even spicier! println!("After extra mirchi: {}", level); } println!("Final levels: {:?}", spice_levels); } |
- &vec or &mut vec → borrow the collection
- *level → dereference to mutate
4. For over Strings (Chars or Bytes)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
fn main() { let greeting = "Namaste Hyderabad! 🚀"; // Loop over Unicode characters (recommended) for ch in greeting.chars() { println!("Char: {}", ch); } // Loop over bytes (if you need raw UTF-8) for byte in greeting.bytes() { println!("Byte: {}", byte); } } |
5. for with break and continue (Same as other loops)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
fn main() { for i in 1..=10 { if i == 3 { println!("Skipping 3..."); continue; } println!("Number: {}", i); if i == 7 { println!("Found 7 — stopping early!"); break; } } } |
6. Nested for Loops + Labels (Useful for grids, matrices)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
fn main() { 'outer: for row in 1..=3 { for col in 1..=3 { if row == 2 && col == 2 { println!("Center found — breaking out!"); break 'outer; } print!("({},{}) ", row, col); } println!(); } } |
7. for as Expression? (No — but you can collect results)
for itself is not an expression (doesn’t return value), but you can use iterators + .collect():
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
fn main() { let squares: Vec<i32> = (1..=10) .map(|x| x * x) .collect(); println!("Squares: {:?}", squares); } |
This is the modern Rust way — prefer iterator chains over manual for + push when transforming data.
Quick Comparison Table (Teacher Style)
| Loop | Best For | Manual Counter? | Bounds Checking? | Most Idiomatic in 2026 Rust? |
|---|---|---|---|---|
| for | Known collection / range / iterator | No | Automatic | ★★★★★ (yes!) |
| while | Condition-based, no natural iterator | Yes | Manual | ★★☆☆☆ |
| loop | Infinite / custom control flow | Yes | Manual | ★★★☆☆ |
Summary in Teacher Voice
Rust for loop =
- The go-to loop in modern Rust
- Works on anything iterable (IntoIterator)
- No manual indexing → fewer bugs
- Clean syntax: for item in collection { … }
- Loves ranges (1..=n), .iter(), .enumerate(), .into_iter()
- Safe borrowing (&, &mut) built-in
- Pairs beautifully with .map(), .filter(), .collect() for functional style
Practice challenge for today:
- Print weekdays with numbers using for + enumerate
- Make a vector of temperatures [28, 30, 32, 35, 38] → use for to print “hot” if >32
- Nested for to print a 5×5 multiplication table
Want solutions for these? Or next: iterators in depth (.map, .filter, .fold…)? Or functions + how for works inside them? Or ownership moves inside loops (very important topic)?
Just say the word — your Rust teacher is right here! 🦀🚀
