Complete Guide to Rust For Loops

Introduction to For Loops in Rust

The for loop in Rust is a powerful and expressive construct for iterating over collections, ranges, and any type that implements the Iterator trait. Unlike traditional C-style for loops with initialization, condition, and increment, Rust's for loop is designed to be safe, expressive, and work seamlessly with its ownership system.

Key Concepts

  • Iterator-based: Works with any type that implements Iterator
  • Ownership-aware: Respects borrowing rules
  • Range syntax: Built-in support for numeric ranges
  • Pattern matching: Can destructure items during iteration
  • Zero-cost: Compiles to efficient loops without overhead

1. Basic For Loop Syntax

Simple Range Iteration

fn main() { // Iterate over a range (exclusive of upper bound) for i in 0..5 { println!("i = {}", i); // Prints 0, 1, 2, 3, 4 } // Iterate over inclusive range for i in 0..=5 { println!("i = {}", i); // Prints 0, 1, 2, 3, 4, 5 } // Reverse iteration for i in (0..5).rev() { println!("Reverse i = {}", i); // Prints 4, 3, 2, 1, 0 } // Step by (using step_by) for i in (0..=10).step_by(2) { println!("Even: {}", i); // Prints 0, 2, 4, 6, 8, 10 } }

Iterating Over Collections

fn main() { // Array iteration (by reference) let arr = [1, 2, 3, 4, 5]; for element in &arr { println!("Element: {}", element); } // Vector iteration let vec = vec!["apple", "banana", "cherry"]; for fruit in &vec { println!("Fruit: {}", fruit); } // String iteration (by chars) let text = "hello"; for c in text.chars() { println!("Char: {}", c); } // String iteration (by bytes) for b in text.bytes() { println!("Byte: {}", b); } }

For Loop with Ownership

fn main() { let vec = vec![1, 2, 3, 4, 5]; // Iterate by value (consumes the vector) for element in vec { println!("Element: {}", element); } // println!("{:?}", vec); // Error: vec moved // Iterate by reference (doesn't consume) let vec2 = vec![1, 2, 3]; for element in &vec2 { println!("Element: {}", element); } println!("Still have vec2: {:?}", vec2); // OK // Iterate by mutable reference (can modify) let mut vec3 = vec![1, 2, 3]; for element in &mut vec3 { *element *= 2; } println!("Modified vec3: {:?}", vec3); // [2, 4, 6] }

2. For Loop with Iterators

Using .iter(), .iter_mut(), .into_iter()

fn main() { let numbers = vec![1, 2, 3, 4, 5]; // .iter() - borrows each element for num in numbers.iter() { println!("Borrowed: {}", num); } println!("Still own numbers: {:?}", numbers); // .iter_mut() - mutably borrows each element let mut numbers = vec![1, 2, 3]; for num in numbers.iter_mut() { *num *= 2; } println!("After mutable iteration: {:?}", numbers); // .into_iter() - takes ownership let numbers = vec![1, 2, 3]; for num in numbers.into_iter() { println!("Owned: {}", num); } // println!("{:?}", numbers); // Error: numbers moved // The three forms are equivalent to: let numbers = vec![1, 2, 3]; // &numbers -> .iter() for num in &numbers { println!("{}", num); } // &mut numbers -> .iter_mut() let mut numbers = vec![1, 2, 3]; for num in &mut numbers { *num *= 2; } // numbers -> .into_iter() let numbers = vec![1, 2, 3]; for num in numbers { println!("{}", num); } }

Custom Iterators

struct Counter { count: u32, max: u32, } impl Counter { fn new(max: u32) -> Self { Counter { count: 0, max } } } impl Iterator for Counter { type Item = u32; fn next(&mut self) -> Option<Self::Item> { if self.count < self.max { self.count += 1; Some(self.count) } else { None } } } struct Fibonacci { current: u32, next: u32, } impl Fibonacci { fn new() -> Self { Fibonacci { current: 0, next: 1 } } } impl Iterator for Fibonacci { type Item = u32; fn next(&mut self) -> Option<Self::Item> { let new_next = self.current + self.next; self.current = self.next; self.next = new_next; Some(self.current) } } fn main() { // Using custom Counter iterator for i in Counter::new(5) { println!("Counter: {}", i); } // Using Fibonacci iterator (take first 10) for num in Fibonacci::new().take(10) { println!("Fibonacci: {}", num); } }

3. For Loop with Enumerate and Index

Getting Index with enumerate()

fn main() { let fruits = vec!["apple", "banana", "cherry", "date"]; // Get index and value for (index, fruit) in fruits.iter().enumerate() { println!("Fruit #{}: {}", index + 1, fruit); } // With mutable access let mut numbers = vec![10, 20, 30]; for (index, num) in numbers.iter_mut().enumerate() { *num += index as i32; } println!("After adding index: {:?}", numbers); // Using enumerate with range for (i, j) in (10..=20).step_by(2).enumerate() { println!("Index: {}, Value: {}", i, j); } // Enumerate with patterns let pairs = vec![(1, 2), (3, 4), (5, 6)]; for (index, (x, y)) in pairs.iter().enumerate() { println!("Pair {}: ({}, {})", index, x, y); } }

Traditional Index-based Loops

fn main() { let arr = [1, 2, 3, 4, 5]; // Using range and indexing (less idiomatic) for i in 0..arr.len() { println!("arr[{}] = {}", i, arr[i]); } // With mutable access let mut vec = vec![1, 2, 3, 4, 5]; for i in 0..vec.len() { vec[i] *= 2; } println!("Doubled: {:?}", vec); // When you need to modify based on index let mut numbers = vec![1, 2, 3, 4, 5]; for i in 0..numbers.len() { numbers[i] += i as i32; } println!("Index added: {:?}", numbers); // Accessing multiple elements with index let arr = [1, 2, 3, 4, 5]; for i in 0..arr.len() - 1 { println!("{} + {} = {}", arr[i], arr[i + 1], arr[i] + arr[i + 1]); } }

4. For Loop with Pattern Matching

Destructuring in For Loops

fn main() { // Tuple destructuring let pairs = vec![(1, 2), (3, 4), (5, 6)]; for (x, y) in &pairs { println!("x = {}, y = {}", x, y); } // Struct destructuring struct Point { x: i32, y: i32, } let points = vec![ Point { x: 1, y: 2 }, Point { x: 3, y: 4 }, Point { x: 5, y: 6 }, ]; for Point { x, y } in &points { println!("Point at ({}, {})", x, y); } // Destructuring with renaming for Point { x: a, y: b } in &points { println!("Coordinates: ({}, {})", a, b); } // Nested destructuring let complex = vec![ (1, (2, 3)), (4, (5, 6)), (7, (8, 9)), ]; for (a, (b, c)) in &complex { println!("a = {}, b = {}, c = {}", a, b, c); } }

Pattern Matching with Enums

enum Color { Red, Green, Blue, RGB(u8, u8, u8), Hex(String), } enum Option<T> { Some(T), None, } fn main() { let colors = vec![ Color::Red, Color::Green, Color::RGB(255, 0, 0), Color::Hex("#00FF00".to_string()), Color::Blue, ]; for color in &colors { match color { Color::Red => println!("It's red!"), Color::Green => println!("It's green!"), Color::Blue => println!("It's blue!"), Color::RGB(r, g, b) => println!("RGB: ({}, {}, {})", r, g, b), Color::Hex(h) => println!("Hex: {}", h), } } // Using if let in for loops let options = vec![ Some(1), None, Some(2), Some(3), None, ]; for opt in &options { if let Some(value) = opt { println!("Got value: {}", value); } else { println!("Got None"); } } }

5. For Loop Control Flow

Break and Continue

fn main() { // Break - exit loop early println!("Break example:"); for i in 0..10 { if i == 5 { break; } println!("i = {}", i); } // Continue - skip to next iteration println!("\nContinue example:"); for i in 0..10 { if i % 2 == 0 { continue; } println!("Odd: {}", i); } // Break with value (in loop expressions) let result = loop { break 42; // break returns value }; println!("Loop result: {}", result); // Break from nested loops (with labels) 'outer: for i in 0..5 { for j in 0..5 { if i == 2 && j == 2 { break 'outer; // breaks outer loop } println!("i = {}, j = {}", i, j); } } // Continue with label 'outer: for i in 0..3 { for j in 0..3 { if i == 1 { continue 'outer; // continues outer loop } println!("i = {}, j = {}", i, j); } } }

Complex Control Flow

fn main() { // Early return from function inside loop fn find_first_even(numbers: &[i32]) -> Option<i32> { for &num in numbers { if num % 2 == 0 { return Some(num); } } None } let numbers = vec![1, 3, 5, 7, 8, 9]; match find_first_even(&numbers) { Some(n) => println!("First even: {}", n), None => println!("No evens found"), } // Break with condition let mut sum = 0; for i in 0.. { sum += i; if sum > 100 { println!("Sum exceeded 100 at i = {}", i); break; } } // Using while let inside for let mut stack = vec![1, 2, 3, 4, 5]; for _ in 0..3 { while let Some(top) = stack.pop() { println!("Popped: {}", top); if top == 3 { break; } } } }

6. For Loop with Collections

Working with Vectors

fn main() { let mut numbers = vec![1, 2, 3, 4, 5]; // Modify while iterating for num in &mut numbers { *num *= 2; } println!("Doubled: {:?}", numbers); // Filter and collect let evens: Vec<_> = numbers.iter() .filter(|&&x| x % 2 == 0) .collect(); println!("Evens: {:?}", evens); // Transform and collect let squares: Vec<_> = numbers.iter() .map(|&x| x * x) .collect(); println!("Squares: {:?}", squares); // Remove elements while iterating (use retain) numbers.retain(|&x| x > 5); println!("After retain: {:?}", numbers); // For loop with draining let mut numbers = vec![1, 2, 3, 4, 5]; for num in numbers.drain(..2) { println!("Drained: {}", num); } println!("Remaining: {:?}", numbers); }

Working with HashMaps

use std::collections::HashMap; fn main() { let mut scores = HashMap::new(); scores.insert("Alice", 100); scores.insert("Bob", 80); scores.insert("Charlie", 95); // Iterate over key-value pairs for (name, score) in &scores { println!("{}: {}", name, score); } // Iterate over keys for name in scores.keys() { println!("Name: {}", name); } // Iterate over values for score in scores.values() { println!("Score: {}", score); } // Iterate over mutable values for score in scores.values_mut() { *score += 5; } println!("Updated scores: {:?}", scores); // Modify while iterating for (name, score) in &mut scores { if *score > 90 { println!("{} has an A", name); } } // Drain the map for (name, score) in scores.drain() { println!("Drained: {} -> {}", name, score); } println!("Empty map: {:?}", scores); }

Working with Strings

fn main() { let text = "Hello, World!"; // Iterate over characters for c in text.chars() { print!("{} ", c); } println!(); // Iterate over words for word in text.split_whitespace() { println!("Word: {}", word); } // Iterate over lines let multiline = "Line 1\nLine 2\nLine 3"; for line in multiline.lines() { println!("Line: {}", line); } // Iterate over bytes for byte in text.bytes() { print!("{} ", byte); } println!(); // Iterate over graphemes (requires unicode-segmentation crate) // for grapheme in text.graphemes(true) { // println!("Grapheme: {}", grapheme); // } // Build string with loop let mut result = String::new(); for i in 0..5 { result.push_str(&format!("Line {}\n", i)); } println!("Result:\n{}", result); }

7. Nested For Loops

Basic Nested Loops

fn main() { // Multiplication table for i in 1..=5 { for j in 1..=5 { print!("{:4}", i * j); } println!(); } // 2D array iteration let matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]; for row in &matrix { for val in row { print!("{} ", val); } println!(); } // Triangle pattern for i in 1..=5 { for _ in 0..i { print!("* "); } println!(); } // Nested loops with enumerate for (i, row) in matrix.iter().enumerate() { for (j, val) in row.iter().enumerate() { println!("matrix[{}][{}] = {}", i, j, val); } } }

Cartesian Product and Combinations

fn main() { // Cartesian product let colors = ["red", "green", "blue"]; let sizes = ["S", "M", "L"]; for &color in &colors { for &size in &sizes { println!("{} {}", color, size); } } // All pairs (combinations with repetition) let numbers = [1, 2, 3]; for &a in &numbers { for &b in &numbers { println!("({}, {})", a, b); } } // Unique pairs (combinations without repetition) for i in 0..numbers.len() { for j in i + 1..numbers.len() { println!("({}, {})", numbers[i], numbers[j]); } } // Nested loops with conditions for i in 1..=3 { for j in 1..=3 { if i + j == 4 { println!("{}+{} = 4", i, j); } } } }

8. For Loop with Ranges and Steps

Advanced Range Usage

fn main() { // Different range types let exclusive = 0..5; // 0,1,2,3,4 let inclusive = 0..=5; // 0,1,2,3,4,5 let from = 3..; // 3,4,5,... (infinite) let to = ..5; // 0,1,2,3,4 (requires start) // Using step_by for i in (0..=20).step_by(3) { println!("Step 3: {}", i); } // Reverse ranges for i in (0..=10).rev() { println!("Reverse: {}", i); } // Combining step and reverse for i in (0..=20).rev().step_by(3) { println!("Reverse step 3: {}", i); } // Custom step function fn step_range(start: i32, end: i32, step: i32) -> impl Iterator<Item = i32> { (start..=end).filter(move |&x| (x - start) % step == 0) } for i in step_range(0, 20, 4) { println!("Custom step: {}", i); } // Chaining ranges let combined = (1..=3).chain(10..=12); for i in combined { println!("Chained: {}", i); } }

Infinite Ranges and Take

fn main() { // Infinite range with take for i in (0..).take(5) { println!("First 5: {}", i); } // Infinite step range for i in (0..).step_by(3).take(5) { println!("Multiples of 3: {}", i); } // Cycle through iterator let colors = ["red", "green", "blue"]; for color in colors.iter().cycle().take(10) { println!("Color: {}", color); } // Fibonacci with infinite iterator let fib = std::iter::successors(Some((0, 1)), |&(a, b)| Some((b, a + b))) .map(|(a, _)| a); for num in fib.take(10) { println!("Fib: {}", num); } // Generate with iterate let powers = std::iter::successors(Some(1), |&n| Some(n * 2)); for num in powers.take(10) { println!("Power of 2: {}", num); } }

9. For Loop with Functional Programming

Using Iterator Adaptors

fn main() { let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // Map let doubled: Vec<_> = numbers.iter().map(|x| x * 2).collect(); println!("Doubled: {:?}", doubled); // Filter let evens: Vec<_> = numbers.iter().filter(|&&x| x % 2 == 0).collect(); println!("Evens: {:?}", evens); // Filter and map let doubled_evens: Vec<_> = numbers.iter() .filter(|&&x| x % 2 == 0) .map(|&x| x * 2) .collect(); println!("Doubled evens: {:?}", doubled_evens); // Fold (reduce) let sum = numbers.iter().fold(0, |acc, &x| acc + x); println!("Sum: {}", sum); // Any and all let has_even = numbers.iter().any(|&x| x % 2 == 0); let all_positive = numbers.iter().all(|&x| x > 0); println!("Has even: {}, All positive: {}", has_even, all_positive); // Find if let Some(first_even) = numbers.iter().find(|&&x| x % 2 == 0) { println!("First even: {}", first_even); } // Position if let Some(pos) = numbers.iter().position(|&x| x == 5) { println!("5 found at position: {}", pos); } // Min and max println!("Min: {:?}", numbers.iter().min()); println!("Max: {:?}", numbers.iter().max()); }

Chaining Operations

fn main() { let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // Complex pipeline let result: i32 = numbers.iter() .filter(|&&x| x % 2 == 0) // Keep evens .map(|&x| x * x) // Square them .filter(|&x| x > 20) // Keep >20 .take(2) // Take first 2 .sum(); // Sum them println!("Pipeline result: {}", result); // Working with Option let optional_numbers = vec![Some(1), None, Some(2), Some(3), None, Some(4)]; let sum: i32 = optional_numbers.iter() .filter_map(|&x| x) // Keep only Some values .map(|x| x * 2) // Double them .sum(); // Sum println!("Filter map sum: {}", sum); // Flat map let words = vec!["hello", "world"]; let chars: Vec<char> = words.iter() .flat_map(|&s| s.chars()) // Flatten chars .collect(); println!("Chars: {:?}", chars); // Zip let names = vec!["Alice", "Bob", "Charlie"]; let ages = vec![30, 25, 35]; let people: Vec<_> = names.iter() .zip(ages.iter()) .collect(); println!("People: {:?}", people); }

10. Performance Considerations

Loop Optimization

fn main() { // Pre-allocate capacity for better performance let mut vec = Vec::with_capacity(1000); for i in 0..1000 { vec.push(i); } // Cache length for repeated bounds checks let arr = [1, 2, 3, 4, 5]; let len = arr.len(); // Cache the length for i in 0..len { println!("arr[{}] = {}", i, arr[i]); } // Using iterators is usually as fast as manual loops let numbers: Vec<i32> = (0..1000).collect(); // Manual loop let start = std::time::Instant::now(); let mut sum1 = 0; for i in 0..numbers.len() { sum1 += numbers[i]; } println!("Manual loop: {:?}", start.elapsed()); // Iterator let start = std::time::Instant::now(); let sum2: i32 = numbers.iter().sum(); println!("Iterator: {:?}", start.elapsed()); // For large collections, consider parallel iterators with rayon // use rayon::prelude::*; // let sum3: i32 = numbers.par_iter().sum(); }

Memory Access Patterns

fn main() { // Row-major vs column-major access let size = 1000; let matrix = vec![vec![0; size]; size]; // Good: Row-major (cache-friendly) let start = std::time::Instant::now(); let mut sum1 = 0; for i in 0..size { for j in 0..size { sum1 += matrix[i][j]; } } println!("Row-major: {:?}", start.elapsed()); // Bad: Column-major (cache- unfriendly) let start = std::time::Instant::now(); let mut sum2 = 0; for j in 0..size { for i in 0..size { sum2 += matrix[i][j]; } } println!("Column-major: {:?}", start.elapsed()); // Using iterators is often optimized let start = std::time::Instant::now(); let sum3: i32 = matrix.iter() .flat_map(|row| row.iter()) .sum(); println!("Iterator: {:?}", start.elapsed()); }

11. For Loop with Concurrency

Rayon Parallel Iterators

// Add rayon = "1.7" to Cargo.toml use rayon::prelude::*; fn main() { let numbers: Vec<i32> = (0..1_000_000).collect(); // Sequential sum let start = std::time::Instant::now(); let sum_seq: i32 = numbers.iter().sum(); println!("Sequential sum: {:?}", start.elapsed()); // Parallel sum let start = std::time::Instant::now(); let sum_par: i32 = numbers.par_iter().sum(); println!("Parallel sum: {:?}", start.elapsed()); // Parallel map and filter let results: Vec<_> = numbers.par_iter() .filter(|&&x| x % 2 == 0) .map(|&x| x * x) .collect(); println!("Parallel results length: {}", results.len()); // Parallel fold let sum = numbers.par_iter() .fold(|| 0, |acc, &x| acc + x) .sum::<i32>(); println!("Parallel fold sum: {}", sum); }

Channels and For Loops

use std::sync::mpsc; use std::thread; fn main() { let (tx, rx) = mpsc::channel(); // Spawn producer thread let producer = thread::spawn(move || { for i in 0..10 { tx.send(i).unwrap(); thread::sleep(std::time::Duration::from_millis(100)); } }); // Receive in for loop for received in rx { println!("Got: {}", received); } producer.join().unwrap(); // Multiple producers let (tx, rx) = mpsc::channel(); let mut handles = vec![]; for id in 0..3 { let tx_clone = tx.clone(); handles.push(thread::spawn(move || { for i in 0..5 { tx_clone.send(format!("Thread {}: {}", id, i)).unwrap(); thread::sleep(std::time::Duration::from_millis(50)); } })); } // Drop original sender drop(tx); // Receive from all threads for message in rx { println!("{}", message); } for handle in handles { handle.join().unwrap(); } }

12. For Loop with Error Handling

Handling Results in Loops

use std::fs::File; use std::io::{self, BufRead}; fn main() -> io::Result<()> { // Reading lines from a file let file = File::open("example.txt")?; let reader = io::BufReader::new(file); for (index, line) in reader.lines().enumerate() { match line { Ok(content) => println!("Line {}: {}", index + 1, content), Err(e) => eprintln!("Error reading line {}: {}", index + 1, e), } } // Collecting Results into a Result<Vec> let numbers = vec!["42", "24", "abc", "12"]; let parsed: Result<Vec<i32>, _> = numbers.iter() .map(|s| s.parse::<i32>()) .collect(); match parsed { Ok(nums) => println!("Parsed numbers: {:?}", nums), Err(e) => println!("Parse error: {}", e), } // Filtering out errors let successful: Vec<i32> = numbers.iter() .filter_map(|s| s.parse::<i32>().ok()) .collect(); println!("Successful: {:?}", successful); // Short-circuit on first error let result: Result<Vec<i32>, _> = numbers.iter() .map(|s| s.parse::<i32>()) .collect::<Result<Vec<_>, _>>(); match result { Ok(nums) => println!("All valid: {:?}", nums), Err(e) => println!("First error: {}", e), } Ok(()) }

Fallible Operations in Loops

use std::fs; use std::io; fn process_files() -> io::Result<()> { let filenames = vec!["file1.txt", "file2.txt", "file3.txt"]; let mut errors = Vec::new(); for filename in &filenames { match fs::read_to_string(filename) { Ok(content) => println!("{}: {} bytes", filename, content.len()), Err(e) => errors.push((filename, e)), } } if !errors.is_empty() { for (filename, error) in errors { eprintln!("Error reading {}: {}", filename, error); } } Ok(()) } // Using try_blocks for early return on error #![feature(try_blocks)] fn process_all_or_none() -> Result<Vec<String>, io::Error> { let filenames = vec!["file1.txt", "file2.txt", "file3.txt"]; let result: Result<Vec<_>, _> = try { let mut contents = Vec::new(); for filename in filenames { contents.push(fs::read_to_string(filename)?); } contents }; result } fn main() { match process_files() { Ok(()) => println!("Processing complete"), Err(e) => println!("IO error: {}", e), } // This will return at first error match process_all_or_none() { Ok(contents) => println!("All files read: {} files", contents.len()), Err(e) => println!("Failed: {}", e), } }

13. Advanced For Loop Patterns

Custom Loop Transformations

fn main() { // Pairs (window of size 2) let numbers = vec![1, 2, 3, 4, 5]; for window in numbers.windows(2) { println!("Window: {:?}", window); println!("Sum: {}", window[0] + window[1]); } // Chunks let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8]; for chunk in numbers.chunks(3) { println!("Chunk: {:?}", chunk); } // Chunks with mutable access let mut numbers = vec![1, 2, 3, 4, 5, 6]; for chunk in numbers.chunks_mut(2) { for num in chunk.iter_mut() { *num *= 2; } } println!("After chunks_mut: {:?}", numbers); // Group by (requires itertools) // use itertools::Itertools; // for (key, group) in &numbers.iter().group_by(|&&x| x % 2 == 0) { // println!("Group {}: {:?}", key, group.collect::<Vec<_>>()); // } }

Stateful Iteration

struct StateMachine { state: i32, } impl StateMachine { fn new() -> Self { StateMachine { state: 0 } } } impl Iterator for StateMachine { type Item = i32; fn next(&mut self) -> Option<Self::Item> { self.state += 1; if self.state <= 5 { Some(self.state) } else { None } } } fn main() { // Scan (stateful map) let numbers = vec![1, 2, 3, 4, 5]; let running_sum: Vec<_> = numbers.iter() .scan(0, |acc, &x| { *acc += x; Some(*acc) }) .collect(); println!("Running sum: {:?}", running_sum); // Custom stateful iterator for state in StateMachine::new() { println!("State: {}", state); } // Fold with state let sum = numbers.iter() .fold(0, |acc, &x| acc + x); println!("Fold sum: {}", sum); // Try_fold (short-circuiting fold) let result = numbers.iter() .try_fold(0, |acc, &x| { if x == 3 { None } else { Some(acc + x) } }); match result { Some(sum) => println!("Sum until error: {}", sum), None => println!("Stopped at 3"), } }

Conclusion

The for loop in Rust is a versatile and powerful construct that goes far beyond simple iteration:

Key Takeaways

  1. Iterator-based: Works seamlessly with any iterable type
  2. Ownership-aware: Respects borrowing rules with .iter(), .iter_mut(), .into_iter()
  3. Range syntax: 0..5 (exclusive) and 0..=5 (inclusive) ranges
  4. Pattern matching: Destructure tuples, structs, and enums directly
  5. Control flow: break, continue, and loop labels
  6. Functional composition: Chain iterator adaptors for complex operations
  7. Zero-cost: Compiles to efficient code comparable to manual loops

Common Patterns

  • Range iteration: for i in 0..n
  • Collection iteration: for item in &collection
  • Indexed iteration: for (i, item) in collection.iter().enumerate()
  • Nested loops: With labels for breaking outer loops
  • Parallel iteration: Using rayon for concurrent processing
  • Error handling: Collecting Results or short-circuiting

Best Practices

  1. Prefer iterators over manual indexing when possible
  2. Use enumerate() when you need indices
  3. Choose the right ownership: Use &collection, &mut collection, or collection appropriately
  4. Chain adaptors for complex transformations
  5. Cache collection lengths when using manual indexing
  6. Use break with labels for nested loops
  7. Consider parallel iterators for CPU-bound operations on large datasets

The for loop in Rust embodies the language's philosophy of combining safety, expressiveness, and performance, making it an essential tool in every Rust programmer's toolkit.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper