Complete Guide to Rust Loops

Introduction to Loops in Rust

Loops are fundamental control flow structures that allow code execution to repeat multiple times. Rust provides several powerful looping constructs, each designed for different scenarios. Understanding loops is essential for writing efficient, readable, and idiomatic Rust code.

Types of Loops in Rust

  • loop: Infinite loops that can break with a value
  • while: Condition-based loops
  • for: Collection iteration loops (most common)
  • while let: Pattern-matching loops

Key Concepts

  • Iteration: Repeating code execution
  • Control flow: break, continue, and loop labels
  • Performance: Zero-cost abstractions
  • Safety: Bounds checking and iterator guarantees
  • Expressiveness: Different loops for different purposes

1. The loop Keyword

Basic Infinite Loops

fn main() {
// Basic infinite loop
let mut counter = 0;
loop {
println!("Iteration {}", counter);
counter += 1;
if counter >= 5 {
break;  // Exit the loop
}
}
// Loop with condition inside
let mut x = 10;
loop {
x -= 1;
if x == 0 {
break;
}
println!("x = {}", x);
}
}

Returning Values from Loops

fn main() {
// Loop can return a value with break
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;  // Returns 20
}
};
println!("Result from loop: {}", result); // 20
// Practical example: finding a value
let numbers = [1, 3, 5, 7, 9, 11, 13];
let mut index = 0;
let found = loop {
if index >= numbers.len() {
break None;
}
if numbers[index] == 7 {
break Some(index);
}
index += 1;
};
match found {
Some(i) => println!("Found 7 at index {}", i),
None => println!("7 not found"),
}
}

Nested Loops and Labels

fn main() {
// Nested loops with labels
let mut count = 0;
'outer: loop {
println!("Outer loop: count = {}", count);
let mut remaining = 3;
'inner: loop {
println!("    Inner loop: remaining = {}", remaining);
remaining -= 1;
if remaining == 0 {
break 'inner;  // Break inner loop
}
if count == 2 {
println!("    Breaking outer loop");
break 'outer;  // Break outer loop
}
}
count += 1;
}
// Another example with nested loops
let mut matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
let target = 5;
let mut found_at = None;
'search: for (i, row) in matrix.iter().enumerate() {
for (j, &value) in row.iter().enumerate() {
if value == target {
found_at = Some((i, j));
break 'search;
}
}
}
println!("Found at: {:?}", found_at);
}

2. The while Loop

Basic While Loops

fn main() {
// Simple while loop
let mut count = 0;
while count < 5 {
println!("count = {}", count);
count += 1;
}
// While with complex condition
let mut x = 10;
let mut y = 0;
while x > 0 && y < 5 {
println!("x: {}, y: {}", x, y);
x -= 2;
y += 1;
}
// While with break
let mut numbers = vec![1, 2, 3, 4, 5];
let mut sum = 0;
while let Some(num) = numbers.pop() {
sum += num;
if sum > 10 {
println!("Sum exceeded 10: {}", sum);
break;
}
}
}

While vs Loop

fn main() {
// When to use loop vs while
// Use loop for infinite or conditional break inside
let mut count = 0;
loop {
count += 1;
if count >= 5 {
break;
}
}
// Use while for condition-based looping
let mut count = 0;
while count < 5 {
count += 1;
}
// Both compile to similar code, but while is more idiomatic
// for simple condition checks
// Performance comparison (usually identical)
let mut i = 0;
while i < 1_000_000 {
i += 1;
}
let mut i = 0;
loop {
if i >= 1_000_000 {
break;
}
i += 1;
}
}

3. The for Loop

Basic For Loops

fn main() {
// For loop over range
for i in 0..5 {
println!("i = {}", i);
}
// Inclusive range
for i in 1..=5 {
println!("i (inclusive) = {}", i);
}
// For loop with step (using step_by)
for i in (0..10).step_by(2) {
println!("Even: {}", i);
}
// Reverse range
for i in (0..5).rev() {
println!("Reverse: {}", i);
}
// For loop with enumerate
let items = vec!["a", "b", "c", "d"];
for (index, value) in items.iter().enumerate() {
println!("items[{}] = {}", index, value);
}
// For loop over array
let array = [10, 20, 30, 40, 50];
for element in array.iter() {
println!("Element: {}", element);
}
// Mutable iteration
let mut numbers = vec![1, 2, 3, 4, 5];
for num in numbers.iter_mut() {
*num *= 2;
}
println!("Doubled: {:?}", numbers);
}

For Loops with Collections

fn main() {
// Vector iteration
let vec = vec!["apple", "banana", "cherry"];
// By reference (most common)
for fruit in &vec {
println!("Fruit: {}", fruit);
}
// By value (consumes the vector)
for fruit in vec {
println!("Fruit (consumed): {}", fruit);
}
// println!("{:?}", vec); // Error: vec moved
// HashMap iteration
use std::collections::HashMap;
let mut map = HashMap::new();
map.insert("Alice", 25);
map.insert("Bob", 30);
map.insert("Charlie", 35);
for (name, age) in &map {
println!("{} is {} years old", name, age);
}
// String iteration
let text = "Hello, World!";
for c in text.chars() {
print!("{} ", c);
}
println!();
for word in text.split_whitespace() {
println!("Word: {}", word);
}
// Custom collection iteration
#[derive(Debug)]
struct Range {
start: i32,
end: i32,
}
impl Range {
fn iter(&self) -> RangeIter {
RangeIter {
current: self.start,
end: self.end,
}
}
}
struct RangeIter {
current: i32,
end: i32,
}
impl Iterator for RangeIter {
type Item = i32;
fn next(&mut self) -> Option<Self::Item> {
if self.current < self.end {
let value = self.current;
self.current += 1;
Some(value)
} else {
None
}
}
}
let range = Range { start: 5, end: 10 };
for i in range.iter() {
println!("Custom range: {}", i);
}
}

4. The while let Loop

Pattern Matching Loops

fn main() {
// while let with Option
let mut numbers = vec![1, 2, 3, 4, 5];
while let Some(num) = numbers.pop() {
println!("Popped: {}", num);
}
// while let with Result
let mut results = vec![Ok(1), Ok(2), Err("error"), Ok(3)];
while let Ok(num) = results.pop() {
println!("Success: {}", num);
}
// while let with custom enum
enum State {
Processing(i32),
Done,
}
let mut state = State::Processing(0);
while let State::Processing(count) = state {
println!("Processing: {}", count);
if count >= 5 {
state = State::Done;
} else {
state = State::Processing(count + 1);
}
}
// while let with multiple patterns
let mut pairs = vec![(1, 2), (3, 4), (5, 6)];
while let Some((x, y)) = pairs.pop() {
println!("Pair: ({}, {})", x, y);
}
// while let with references
let mut data = vec![Some(1), Some(2), None, Some(3)];
let mut iter = data.iter_mut();
while let Some(Some(value)) = iter.next() {
*value *= 10;
}
println!("Modified: {:?}", data);
}

Advanced while let Patterns

fn main() {
// while let with destructuring
#[derive(Debug)]
struct Container {
items: Vec<Option<i32>>,
}
let mut containers = vec![
Container { items: vec![Some(1), None, Some(2)] },
Container { items: vec![Some(3), Some(4)] },
];
while let Some(container) = containers.pop() {
println!("Processing container: {:?}", container);
let mut items = container.items;
while let Some(Some(val)) = items.pop() {
println!("  Value: {}", val);
}
}
// while let with guards (using match inside)
let mut numbers = vec![1, 2, 3, 4, 5, 6];
while let Some(num) = numbers.pop() {
match num {
n if n % 2 == 0 => println!("Even: {}", n),
_ => continue,
}
}
// Nested while let
let mut nested = vec![vec![1, 2], vec![3, 4], vec![5, 6]];
while let Some(mut inner) = nested.pop() {
println!("Outer item");
while let Some(val) = inner.pop() {
println!("  Inner: {}", val);
}
}
}

5. Loop Control: break and continue

Break Statement

fn main() {
// Basic break
let mut count = 0;
loop {
count += 1;
if count == 5 {
break;
}
println!("Count: {}", count);
}
// Break with value
let mut count = 0;
let result = loop {
count += 1;
if count == 5 {
break count * 2;  // Returns 10
}
};
println!("Result: {}", result);
// Break in nested loops
'outer: for i in 0..5 {
for j in 0..5 {
if i == 2 && j == 3 {
println!("Breaking at ({}, {})", i, j);
break 'outer;
}
println!("i: {}, j: {}", i, j);
}
}
// Break in while loop
let mut numbers = vec![1, 2, 3, 4, 5];
let target = 3;
while let Some(num) = numbers.pop() {
if num == target {
println!("Found target: {}", target);
break;
}
println!("Popped: {}", num);
}
}

Continue Statement

fn main() {
// Basic continue
for i in 0..10 {
if i % 2 == 0 {
continue;  // Skip even numbers
}
println!("Odd: {}", i);
}
// Continue in nested loops
'outer: for i in 0..3 {
for j in 0..3 {
if i == 1 && j == 1 {
println!("Skipping i={}, j={}", i, j);
continue 'outer;  // Continue outer loop
}
println!("i: {}, j: {}", i, j);
}
}
// Continue with while
let mut data = vec![1, 2, 3, 4, 5];
let mut sum = 0;
while let Some(num) = data.pop() {
if num == 3 {
println!("Skipping 3");
continue;
}
sum += num;
println!("Added {}, sum = {}", num, sum);
}
// Continue in iterator chain
let numbers = vec![1, 2, 3, 4, 5, 6];
let mut even_squares = Vec::new();
for &num in &numbers {
if num % 2 != 0 {
continue;
}
even_squares.push(num * num);
}
println!("Even squares: {:?}", even_squares);
}

6. Iterators and For Loops

Iterator Adaptors

fn main() {
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// map - transform each element
let squares: Vec<_> = numbers.iter()
.map(|&x| x * x)
.collect();
println!("Squares: {:?}", squares);
// filter - keep elements matching condition
let evens: Vec<_> = numbers.iter()
.filter(|&&x| x % 2 == 0)
.collect();
println!("Evens: {:?}", evens);
// filter_map - combine filter and map
let strings = vec!["1", "2", "three", "4", "five"];
let parsed: Vec<i32> = strings.iter()
.filter_map(|&s| s.parse().ok())
.collect();
println!("Parsed numbers: {:?}", parsed);
// take - limit number of elements
let first_three: Vec<_> = numbers.iter()
.take(3)
.collect();
println!("First three: {:?}", first_three);
// skip - skip elements
let after_five: Vec<_> = numbers.iter()
.skip(5)
.collect();
println!("After five: {:?}", after_five);
// zip - combine two iterators
let names = vec!["Alice", "Bob", "Charlie"];
let ages = vec![25, 30, 35];
let people: Vec<_> = names.iter()
.zip(ages.iter())
.collect();
println!("People: {:?}", people);
// chain - concatenate iterators
let first = vec![1, 2, 3];
let second = vec![4, 5, 6];
let combined: Vec<_> = first.iter()
.chain(second.iter())
.collect();
println!("Combined: {:?}", combined);
}

Consuming Iterators

fn main() {
let numbers = vec![1, 2, 3, 4, 5];
// count - number of elements
let count = numbers.iter().count();
println!("Count: {}", count);
// sum - sum of elements
let sum: i32 = numbers.iter().sum();
println!("Sum: {}", sum);
// product - product of elements
let product: i32 = numbers.iter().product();
println!("Product: {}", product);
// max - maximum element
let max = numbers.iter().max();
println!("Max: {:?}", max);
// min - minimum element
let min = numbers.iter().min();
println!("Min: {:?}", min);
// fold - accumulate with initial value
let sum = numbers.iter().fold(0, |acc, &x| acc + x);
println!("Fold sum: {}", sum);
let factorial = numbers.iter().fold(1, |acc, &x| acc * x);
println!("Fold product: {}", factorial);
// any - check if any element matches
let has_even = numbers.iter().any(|&x| x % 2 == 0);
println!("Has even: {}", has_even);
// all - check if all elements match
let all_positive = numbers.iter().all(|&x| x > 0);
println!("All positive: {}", all_positive);
// find - find first matching element
let first_even = numbers.iter().find(|&&x| x % 2 == 0);
println!("First even: {:?}", first_even);
// position - find index of first match
let pos = numbers.iter().position(|&x| x > 3);
println!("Position of first >3: {:?}", pos);
}

7. Custom Iterators

Implementing Iterator

struct Fibonacci {
current: u64,
next: u64,
}
impl Fibonacci {
fn new() -> Self {
Fibonacci {
current: 0,
next: 1,
}
}
}
impl Iterator for Fibonacci {
type Item = u64;
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)
}
}
struct PrimeIterator {
current: u64,
}
impl PrimeIterator {
fn new() -> Self {
PrimeIterator { current: 2 }
}
fn is_prime(n: u64) -> bool {
if n <= 1 {
return false;
}
if n == 2 {
return true;
}
if n % 2 == 0 {
return false;
}
let mut i = 3;
while i * i <= n {
if n % i == 0 {
return false;
}
i += 2;
}
true
}
}
impl Iterator for PrimeIterator {
type Item = u64;
fn next(&mut self) -> Option<Self::Item> {
while !PrimeIterator::is_prime(self.current) {
self.current += 1;
}
let prime = self.current;
self.current += 1;
Some(prime)
}
}
fn main() {
// Fibonacci iterator
println!("First 10 Fibonacci numbers:");
for (i, num) in Fibonacci::new().take(10).enumerate() {
println!("fib[{}] = {}", i + 1, num);
}
// Prime iterator
println!("\nFirst 10 prime numbers:");
for (i, prime) in PrimeIterator::new().take(10).enumerate() {
println!("prime[{}] = {}", i + 1, prime);
}
// Using iterator methods
let fib_sum: u64 = Fibonacci::new().take(10).sum();
println!("\nSum of first 10 Fibonacci numbers: {}", fib_sum);
let first_prime_above_100 = PrimeIterator::new()
.find(|&p| p > 100);
println!("First prime above 100: {:?}", first_prime_above_100);
}

Iterator Combinators

struct StepBy<I> {
iter: I,
step: usize,
first: bool,
}
impl<I: Iterator> StepBy<I> {
fn new(iter: I, step: usize) -> Self {
StepBy {
iter,
step,
first: true,
}
}
}
impl<I: Iterator> Iterator for StepBy<I> {
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
if self.first {
self.first = false;
self.iter.next()
} else {
self.iter.nth(self.step - 1)
}
}
}
struct Interleave<I, J> {
iter1: I,
iter2: J,
toggle: bool,
}
impl<I, J> Interleave<I, J> {
fn new(iter1: I, iter2: J) -> Self {
Interleave {
iter1,
iter2,
toggle: true,
}
}
}
impl<I, J> Iterator for Interleave<I, J>
where
I: Iterator,
J: Iterator<Item = I::Item>,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
self.toggle = !self.toggle;
if self.toggle {
self.iter1.next()
} else {
self.iter2.next()
}
}
}
fn main() {
let numbers = 0..10;
// Custom step_by
let step_by = StepBy::new(numbers, 3);
println!("Step by 3: {:?}", step_by.collect::<Vec<_>>());
// Interleave two iterators
let evens = (0..10).filter(|&x| x % 2 == 0);
let odds = (0..10).filter(|&x| x % 2 != 0);
let interleaved = Interleave::new(evens, odds);
println!("Interleaved evens and odds: {:?}", 
interleaved.take(10).collect::<Vec<_>>());
}

8. Performance and Optimization

Loop Optimizations

fn main() {
use std::time::Instant;
let data: Vec<i32> = (0..1_000_000).collect();
// For loop with iterator (idiomatic)
let start = Instant::now();
let mut sum1 = 0;
for &x in &data {
sum1 += x;
}
let time1 = start.elapsed();
// While loop with index
let start = Instant::now();
let mut sum2 = 0;
let mut i = 0;
while i < data.len() {
sum2 += data[i];
i += 1;
}
let time2 = start.elapsed();
// Loop with iterator and sum()
let start = Instant::now();
let sum3: i32 = data.iter().sum();
let time3 = start.elapsed();
println!("For loop: {:?}, sum = {}", time1, sum1);
println!("While loop: {:?}, sum = {}", time2, sum2);
println!("Iterator sum: {:?}, sum = {}", time3, sum3);
// Cache-friendly vs cache-unfriendly
let matrix_size = 1000;
let mut matrix = vec![vec![0; matrix_size]; matrix_size];
// Row-major (cache-friendly)
let start = Instant::now();
for i in 0..matrix_size {
for j in 0..matrix_size {
matrix[i][j] += 1;
}
}
println!("Row-major: {:?}", start.elapsed());
// Column-major (cache-unfriendly)
let start = Instant::now();
for j in 0..matrix_size {
for i in 0..matrix_size {
matrix[i][j] += 1;
}
}
println!("Column-major: {:?}", start.elapsed());
}

Loop Unrolling

fn main() {
let data: Vec<i32> = (0..1000).collect();
// Standard loop
let start = std::time::Instant::now();
let mut sum1 = 0;
for &x in &data {
sum1 += x;
}
let time1 = start.elapsed();
// Manually unrolled (rarely needed, compiler does this)
let start = std::time::Instant::now();
let mut sum2 = 0;
let chunks = data.chunks(4);
for chunk in chunks {
if chunk.len() == 4 {
sum2 += chunk[0] + chunk[1] + chunk[2] + chunk[3];
} else {
for &x in chunk {
sum2 += x;
}
}
}
let time2 = start.elapsed();
println!("Standard loop: {:?}", time1);
println!("Unrolled loop: {:?}", time2);
// Using iterators with adaptors (compiler optimizes)
let start = std::time::Instant::now();
let sum3: i32 = data.par_iter().sum(); // Parallel iteration with rayon
let time3 = start.elapsed();
println!("Parallel sum: {:?}", time3);
}

9. Common Loop Patterns

Early Return Pattern

fn find_first_positive(numbers: &[i32]) -> Option<i32> {
for &num in numbers {
if num > 0 {
return Some(num);
}
}
None
}
fn all_positive(numbers: &[i32]) -> bool {
for &num in numbers {
if num <= 0 {
return false;
}
}
true
}
fn process_until_error(data: &[Result<i32, &str>]) -> Vec<i32> {
let mut results = Vec::new();
for item in data {
match item {
Ok(val) => results.push(*val),
Err(_) => break,
}
}
results
}
fn main() {
let numbers = vec![-1, -2, 3, 4, -5];
if let Some(first) = find_first_positive(&numbers) {
println!("First positive: {}", first);
}
println!("All positive: {}", all_positive(&numbers));
let data = vec![Ok(1), Ok(2), Err("error"), Ok(3)];
let processed = process_until_error(&data);
println!("Processed until error: {:?}", processed);
}

Accumulator Pattern

fn running_total(numbers: &[i32]) -> Vec<i32> {
let mut result = Vec::with_capacity(numbers.len());
let mut total = 0;
for &num in numbers {
total += num;
result.push(total);
}
result
}
fn cumulative_product(numbers: &[i32]) -> Vec<i32> {
let mut result = Vec::with_capacity(numbers.len());
let mut product = 1;
for &num in numbers {
product *= num;
result.push(product);
}
result
}
fn moving_average(numbers: &[f64], window: usize) -> Vec<f64> {
if numbers.len() < window {
return Vec::new();
}
let mut result = Vec::new();
for i in 0..=numbers.len() - window {
let window_slice = &numbers[i..i + window];
let avg = window_slice.iter().sum::<f64>() / window as f64;
result.push(avg);
}
result
}
fn main() {
let nums = vec![1, 2, 3, 4, 5];
println!("Running total: {:?}", running_total(&nums));
println!("Cumulative product: {:?}", cumulative_product(&nums));
let floats = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
println!("Moving average (window=3): {:?}", moving_average(&floats, 3));
}

Window Processing

fn sliding_window_max(numbers: &[i32], window_size: usize) -> Vec<i32> {
if numbers.len() < window_size {
return Vec::new();
}
let mut result = Vec::new();
for window in numbers.windows(window_size) {
let max = *window.iter().max().unwrap();
result.push(max);
}
result
}
fn adjacent_differences(numbers: &[i32]) -> Vec<i32> {
numbers.windows(2)
.map(|w| w[1] - w[0])
.collect()
}
fn local_maxima(numbers: &[i32]) -> Vec<(usize, i32)> {
numbers.windows(3)
.enumerate()
.filter_map(|(i, w)| {
if w[1] > w[0] && w[1] > w[2] {
Some((i + 1, w[1]))
} else {
None
}
})
.collect()
}
fn main() {
let numbers = vec![1, 3, 2, 5, 4, 7, 6, 9, 8];
println!("Window max (size 3): {:?}", 
sliding_window_max(&numbers, 3));
println!("Adjacent differences: {:?}", 
adjacent_differences(&numbers));
println!("Local maxima: {:?}", 
local_maxima(&numbers));
}

10. Loops with Concurrency

Parallel Processing

use std::thread;
use std::sync::{Arc, Mutex, mpsc};
fn parallel_map<T, F>(data: Vec<T>, f: F) -> Vec<T::Item>
where
T: Send + 'static,
T::Item: Send + 'static,
F: Fn(T) -> T::Item + Send + Sync + Clone + 'static,
{
let (tx, rx) = mpsc::channel();
let data = Arc::new(Mutex::new(data));
let num_threads = 4;
let mut handles = vec![];
for _ in 0..num_threads {
let data = data.clone();
let tx = tx.clone();
let f = f.clone();
handles.push(thread::spawn(move || {
loop {
let item = {
let mut data = data.lock().unwrap();
if data.is_empty() {
break;
}
data.pop()
};
if let Some(item) = item {
let result = f(item);
tx.send(result).unwrap();
}
}
}));
}
drop(tx); // Close channel
let mut results = vec![];
for received in rx {
results.push(received);
}
for handle in handles {
handle.join().unwrap();
}
results
}
fn main() {
let data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Parallel map
let results = parallel_map(data, |x| {
thread::sleep(std::time::Duration::from_millis(10));
x * x
});
println!("Parallel map results: {:?}", results);
// Channel-based work distribution
let (tx, rx) = mpsc::channel();
// Producer
let producer = thread::spawn(move || {
for i in 0..10 {
tx.send(i).unwrap();
thread::sleep(std::time::Duration::from_millis(50));
}
});
// Consumer with loop
let consumer = thread::spawn(move || {
let mut sum = 0;
for received in rx {
println!("Received: {}", received);
sum += received;
}
sum
});
producer.join().unwrap();
let result = consumer.join().unwrap();
println!("Sum of all received: {}", result);
}

11. Error Handling in Loops

Result Handling

use std::num::ParseIntError;
fn parse_numbers(strings: &[&str]) -> Result<Vec<i32>, ParseIntError> {
let mut numbers = Vec::new();
for &s in strings {
let num = s.parse::<i32>()?;
numbers.push(num);
}
Ok(numbers)
}
fn process_with_retry<F, T>(mut f: F, max_retries: usize) -> Result<T, String>
where
F: FnMut() -> Result<T, String>,
{
let mut last_error = String::new();
for attempt in 1..=max_retries {
println!("Attempt {} of {}", attempt, max_retries);
match f() {
Ok(result) => return Ok(result),
Err(e) => {
last_error = e;
if attempt < max_retries {
println!("Failed: {}. Retrying...", last_error);
}
}
}
}
Err(format!("All {} attempts failed: {}", max_retries, last_error))
}
fn collect_valid_numbers(input: &[&str]) -> Vec<i32> {
let mut valid = Vec::new();
for &s in input {
if let Ok(num) = s.parse::<i32>() {
valid.push(num);
}
}
valid
}
fn main() {
let strings = vec!["1", "2", "three", "4", "five"];
match parse_numbers(&strings) {
Ok(nums) => println!("Parsed: {:?}", nums),
Err(e) => println!("Parse error: {}", e),
}
let valid = collect_valid_numbers(&strings);
println!("Valid numbers: {:?}", valid);
// Retry example
let mut attempts = 0;
let result = process_with_retry(
|| {
attempts += 1;
if attempts < 3 {
Err(format!("Failed on attempt {}", attempts))
} else {
Ok(42)
}
},
5,
);
match result {
Ok(val) => println!("Success: {}", val),
Err(e) => println!("Failure: {}", e),
}
}

12. Loops in Functional Programming

Functional Alternatives to Loops

fn main() {
let numbers = vec![1, 2, 3, 4, 5];
// Imperative approach
let mut squares_imperative = Vec::new();
for &x in &numbers {
squares_imperative.push(x * x);
}
// Functional approach
let squares_functional: Vec<i32> = numbers.iter()
.map(|&x| x * x)
.collect();
assert_eq!(squares_imperative, squares_functional);
// Filtering
let evens_imperative = Vec::new();
let mut evens = Vec::new();
for &x in &numbers {
if x % 2 == 0 {
evens.push(x);
}
}
let evens_functional: Vec<i32> = numbers.iter()
.filter(|&&x| x % 2 == 0)
.copied()
.collect();
// Reducing
let sum_imperative = {
let mut sum = 0;
for &x in &numbers {
sum += x;
}
sum
};
let sum_functional: i32 = numbers.iter().sum();
let sum_fold = numbers.iter().fold(0, |acc, &x| acc + x);
// Complex transformations
let data = vec![
"1", "2", "three", "4", "five", "6"
];
// Imperative
let mut result_imperative = Vec::new();
for s in data {
if let Ok(num) = s.parse::<i32>() {
if num % 2 == 0 {
result_imperative.push(num * num);
}
}
}
// Functional
let result_functional: Vec<i32> = data.iter()
.filter_map(|&s| s.parse::<i32>().ok())
.filter(|&num| num % 2 == 0)
.map(|num| num * num)
.collect();
println!("Imperative: {:?}", result_imperative);
println!("Functional: {:?}", result_functional);
}

Conclusion

Rust's loop constructs provide powerful and safe ways to repeat code execution:

Key Takeaways

  1. loop: For infinite loops that need to break with values
  2. while: For condition-based repetition
  3. for: For iterating over collections (most common)
  4. while let: For pattern-matching loops
  5. Break/Continue: With labels for nested control flow
  6. Iterators: Functional approach to looping
  7. Performance: Zero-cost abstractions with compiler optimizations

Best Practices

  1. Use for loops when iterating over collections
  2. Use while loops for condition-based logic
  3. Use loop for infinite loops or when returning values
  4. Use iterators and adaptors for complex transformations
  5. Prefer break with values over mutable state
  6. Use loop labels for clarity in nested loops
  7. Consider while let for Option/Result iteration

Performance Tips

  1. Prefer iterators over manual indexing
  2. Use for loops - they're idiomatic and optimized
  3. Let the compiler unroll loops automatically
  4. Use chunks or windows for batch processing
  5. Consider parallel iterators for large datasets
  6. Profile before optimizing - compilers are smart

Rust's loop constructs, combined with its powerful iterator system, provide everything needed to write efficient, expressive, and safe iterative code.

Leave a Reply

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


Macro Nepal Helper