Complete Guide to Rust While Loops

Introduction to While Loops in Rust

While loops are fundamental control flow structures that execute a block of code repeatedly as long as a condition remains true. Rust provides several looping constructs, with while being one of the most flexible and commonly used. Understanding while loops is essential for writing efficient, readable, and idiomatic Rust code.

Key Concepts

  • Condition-based: Continues while condition is true
  • Pre-test loop: Condition checked before each iteration
  • Flexible termination: Can break based on any condition
  • Pattern matching: while let for destructuring patterns
  • Zero-cost abstraction: Compiles to efficient machine code
  • Safety: Prevents common loop-related bugs

1. Basic While Loop

Simple While Loop

fn main() {
// Basic while loop
let mut counter = 0;
while counter < 5 {
println!("Counter: {}", counter);
counter += 1;
}
// While loop 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;
}
// Infinite while loop (with break)
let mut count = 0;
while true {  // or simply `loop` is better for infinite loops
println!("Iteration {}", count);
count += 1;
if count >= 3 {
break;
}
}
}

While vs Loop

fn main() {
// `loop` for infinite loops (preferred)
let mut count = 0;
loop {
count += 1;
if count == 3 {
break;
}
}
// `while` for condition-based loops
let mut count = 0;
while count < 3 {
count += 1;
}
// Performance comparison (usually identical)
let mut i = 0;
while i < 1000000 {
i += 1;
}
let mut i = 0;
loop {
if i >= 1000000 {
break;
}
i += 1;
}
}

2. While Let Loops

Pattern Matching with while let

fn main() {
// while let with Option
let mut numbers = vec![1, 2, 3, 4, 5].into_iter();
while let Some(num) = numbers.next() {
println!("Number: {}", num);
}
// while let with Result (continues while Ok)
let mut results = vec![Ok(1), Ok(2), Err("error"), Ok(3)];
let mut iter = results.into_iter();
while let Ok(num) = iter.next() {
println!("Success: {}", num);
}
// while let with custom enum
enum State {
Running(i32),
Paused,
Stopped,
}
let mut state = State::Running(0);
while let State::Running(count) = state {
println!("Running, count: {}", count);
if count >= 5 {
state = State::Stopped;
} else {
state = State::Running(count + 1);
}
}
// while let with multiple patterns
let mut pairs = vec![(1, 2), (3, 4), (5, 6)];
let mut iter = pairs.into_iter();
while let Some((x, y)) = iter.next() {
println!("Pair: ({}, {})", x, y);
}
}

Advanced while let Patterns

fn main() {
// 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 *= 2;
}
println!("Modified data: {:?}", data);
// while let with guards (not directly supported, use match inside)
let mut numbers = vec![1, 2, 3, 4, 5, 6];
let mut iter = numbers.iter_mut();
while let Some(num) = iter.next() {
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]];
let mut outer_iter = nested.iter_mut();
while let Some(inner_vec) = outer_iter.next() {
let mut inner_iter = inner_vec.iter_mut();
while let Some(val) = inner_iter.next() {
*val *= 10;
}
}
println!("Nested modified: {:?}", nested);
// while let with complex 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)] },
];
let mut container_iter = containers.iter_mut();
while let Some(container) = container_iter.next() {
let mut item_iter = container.items.iter_mut();
while let Some(Some(val)) = item_iter.next() {
*val += 100;
}
}
println!("Containers: {:?}", containers);
}

3. Loop Control with break and continue

Break Statement

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

Continue Statement

fn main() {
// Basic continue
let mut count = 0;
while count < 10 {
count += 1;
if count % 2 == 0 {
continue;  // Skip even numbers
}
println!("Odd number: {}", count);
}
// Continue in nested loops
let mut i = 0;
while i < 3 {
i += 1;
let mut j = 0;
while j < 3 {
j += 1;
if i == 2 && j == 2 {
println!("Skipping i={}, j={}", i, j);
continue;
}
println!("i: {}, j: {}", i, j);
}
}
// Continue with label
let mut i = 0;
'outer: while i < 3 {
i += 1;
let mut j = 0;
while j < 3 {
j += 1;
if i == 2 && j == 2 {
println!("Continuing outer at i={}, j={}", i, j);
continue 'outer;
}
println!("i: {}, j: {}", i, j);
}
}
// Continue in while let
let mut data = vec![Some(1), None, Some(2), None, Some(3)];
let mut iter = data.iter();
while let Some(item) = iter.next() {
if item.is_none() {
println!("Skipping None");
continue;
}
println!("Processing: {:?}", item);
}
}

4. While Loops with Collections

Iterating with While

fn main() {
// While loop with vector (not idiomatic, but possible)
let numbers = vec![1, 2, 3, 4, 5];
let mut index = 0;
while index < numbers.len() {
println!("numbers[{}] = {}", index, numbers[index]);
index += 1;
}
// Better: while let with iterator
let mut iter = numbers.iter();
while let Some(num) = iter.next() {
println!("Number: {}", num);
}
// Modifying while iterating
let mut numbers = vec![1, 2, 3, 4, 5];
let mut iter = numbers.iter_mut();
while let Some(num) = iter.next() {
*num *= 2;
}
println!("Doubled: {:?}", numbers);
// Multiple collections
let names = vec!["Alice", "Bob", "Charlie"];
let ages = vec![25, 30, 35];
let mut name_iter = names.iter();
let mut age_iter = ages.iter();
while let (Some(name), Some(age)) = (name_iter.next(), age_iter.next()) {
println!("{} is {} years old", name, age);
}
// Filtering with while
let mut numbers = vec![1, 2, 3, 4, 5, 6];
let mut even_sum = 0;
let mut iter = numbers.iter();
while let Some(num) = iter.next() {
if num % 2 == 0 {
even_sum += num;
}
}
println!("Sum of evens: {}", even_sum);
}

While with Custom Iterators

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 Range {
start: i32,
end: i32,
current: i32,
}
impl Range {
fn new(start: i32, end: i32) -> Self {
Range {
start,
end,
current: start,
}
}
}
impl Iterator for Range {
type Item = i32;
fn next(&mut self) -> Option<Self::Item> {
if self.current < self.end {
let result = self.current;
self.current += 1;
Some(result)
} else {
None
}
}
}
fn main() {
// Using while with custom iterator
let mut fib = Fibonacci::new();
println!("First 10 Fibonacci numbers:");
let mut count = 0;
while let Some(num) = fib.next() {
if count >= 10 {
break;
}
println!("fib[{}] = {}", count, num);
count += 1;
}
// Custom range iterator
let mut range = Range::new(5, 10);
println!("Range 5..10:");
while let Some(num) = range.next() {
println!("{}", num);
}
}

5. While Loops with Input/Output

Reading Input with While

use std::io::{self, Write};
fn main() {
// Reading lines until empty input
println!("Enter lines (empty line to quit):");
let mut lines = Vec::new();
loop {
print!("> ");
io::stdout().flush().unwrap();
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Failed to read line");
let input = input.trim();
if input.is_empty() {
break;
}
lines.push(input.to_string());
}
println!("You entered: {:?}", lines);
// Reading numbers until invalid input
let mut numbers = Vec::new();
let mut input = String::new();
println!("Enter numbers (one per line, 'done' to finish):");
while {
print!("num> ");
io::stdout().flush().unwrap();
input.clear();
io::stdin().read_line(&mut input).is_ok()
} {
let input = input.trim();
if input == "done" {
break;
}
if let Ok(num) = input.parse::<i32>() {
numbers.push(num);
} else {
println!("Invalid number, try again");
}
}
println!("Numbers: {:?}", numbers);
}

File Processing with While

use std::fs::File;
use std::io::{self, BufRead, BufReader, Write};
fn main() -> io::Result<()> {
// Reading file line by line
let file = File::open("sample.txt")?;
let reader = BufReader::new(file);
let mut lines = reader.lines();
let mut line_number = 1;
while let Some(line) = lines.next() {
let line = line?;
println!("Line {}: {}", line_number, line);
line_number += 1;
}
// Processing file with condition
let file = File::open("data.txt")?;
let reader = BufReader::new(file);
let mut lines = reader.lines();
let mut valid_lines = 0;
while let Some(line) = lines.next() {
let line = line?;
if line.starts_with('#') {
continue;  // Skip comments
}
if line.is_empty() {
break;  // Stop at empty line
}
println!("Data: {}", line);
valid_lines += 1;
}
println!("Processed {} valid lines", valid_lines);
// Writing with while
let mut file = File::create("output.txt")?;
let mut i = 0;
while i < 10 {
writeln!(file, "Line {}", i)?;
i += 1;
}
Ok(())
}

6. While Loops with Error Handling

Error Handling Patterns

use std::num::ParseIntError;
fn main() {
// While loop with Result
let inputs = vec!["10", "20", "30", "40", "50"];
let mut iter = inputs.iter();
let mut sum = 0;
while let Some(input) = iter.next() {
match input.parse::<i32>() {
Ok(num) => {
sum += num;
println!("Added {}, sum = {}", num, sum);
}
Err(e) => {
println!("Error parsing '{}': {}", input, e);
break;
}
}
}
// While with ? operator (in function that returns Result)
fn process_numbers() -> Result<Vec<i32>, ParseIntError> {
let inputs = vec!["1", "2", "three", "4", "5"];
let mut iter = inputs.iter();
let mut results = Vec::new();
while let Some(input) = iter.next() {
let num = input.parse::<i32>()?;  // Propagates error
results.push(num);
}
Ok(results)
}
match process_numbers() {
Ok(nums) => println!("Processed: {:?}", nums),
Err(e) => println!("Error: {}", e),
}
// Retry pattern with while
let mut attempts = 0;
let max_attempts = 3;
let mut success = false;
while attempts < max_attempts && !success {
attempts += 1;
println!("Attempt {} of {}", attempts, max_attempts);
// Simulate operation that might fail
let result: Result<i32, &str> = if attempts == 3 {
Ok(42)
} else {
Err("temporary failure")
};
match result {
Ok(value) => {
println!("Success after {} attempts: {}", attempts, value);
success = true;
}
Err(e) => {
println!("Attempt {} failed: {}", attempts, e);
if attempts < max_attempts {
println!("Retrying...");
}
}
}
}
if !success {
println!("All attempts failed");
}
}

7. While Loops with Concurrency

Simple Thread Synchronization

use std::sync::{Arc, Mutex, atomic::{AtomicBool, Ordering}};
use std::thread;
use std::time::Duration;
fn main() {
// Shared flag between threads
let running = Arc::new(AtomicBool::new(true));
let counter = Arc::new(Mutex::new(0));
let running_clone = running.clone();
let counter_clone = counter.clone();
// Worker thread
let handle = thread::spawn(move || {
while running_clone.load(Ordering::SeqCst) {
let mut num = counter_clone.lock().unwrap();
*num += 1;
println!("Worker incremented to: {}", *num);
thread::sleep(Duration::from_millis(100));
}
println!("Worker stopping");
});
// Main thread
for i in 0..5 {
thread::sleep(Duration::from_millis(150));
let num = counter.lock().unwrap();
println!("Main sees counter: {}", *num);
}
// Signal worker to stop
running.store(false, Ordering::SeqCst);
handle.join().unwrap();
// Multiple workers with condition
let tasks = Arc::new(Mutex::new(vec![1, 2, 3, 4, 5]));
let completed = Arc::new(Mutex::new(Vec::new()));
let mut handles = vec![];
for id in 0..3 {
let tasks = tasks.clone();
let completed = completed.clone();
handles.push(thread::spawn(move || {
loop {
let task = {
let mut tasks = tasks.lock().unwrap();
if tasks.is_empty() {
None
} else {
Some(tasks.remove(0))
}
};
match task {
Some(t) => {
println!("Worker {} processing task {}", id, t);
thread::sleep(Duration::from_millis(50));
let mut completed = completed.lock().unwrap();
completed.push(t);
}
None => break,
}
}
println!("Worker {} finished", id);
}));
}
for handle in handles {
handle.join().unwrap();
}
println!("All tasks completed: {:?}", completed.lock().unwrap());
}

Channel Communication

use std::sync::mpsc;
use std::thread;
use std::time::Duration;
fn main() {
// Simple channel with while
let (tx, rx) = mpsc::channel();
let handle = thread::spawn(move || {
for i in 0..5 {
tx.send(i).unwrap();
thread::sleep(Duration::from_millis(100));
}
});
// Receive until channel closes
while let Ok(received) = rx.recv() {
println!("Received: {}", received);
}
handle.join().unwrap();
// Multiple producers
let (tx, rx) = mpsc::channel();
let tx1 = tx.clone();
let tx2 = tx.clone();
thread::spawn(move || {
for i in 0..3 {
tx1.send(format!("Thread 1: {}", i)).unwrap();
thread::sleep(Duration::from_millis(50));
}
});
thread::spawn(move || {
for i in 0..3 {
tx2.send(format!("Thread 2: {}", i)).unwrap();
thread::sleep(Duration::from_millis(30));
}
});
// Receive from multiple threads
for _ in 0..6 {
match rx.recv_timeout(Duration::from_millis(100)) {
Ok(msg) => println!("Got: {}", msg),
Err(e) => println!("Timeout: {}", e),
}
}
}

8. While Loops in Algorithms

Search Algorithms

fn main() {
// Binary search with while
let arr = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19];
let target = 13;
let mut left = 0;
let mut right = arr.len() - 1;
let mut found = None;
while left <= right {
let mid = left + (right - left) / 2;
println!("Searching: left={}, mid={}, right={}", left, mid, right);
if arr[mid] == target {
found = Some(mid);
break;
} else if arr[mid] < target {
left = mid + 1;
} else {
right = mid - 1;
}
}
match found {
Some(index) => println!("Found {} at index {}", target, index),
None => println!("{} not found", target),
}
// Linear search with while
let data = [4, 2, 7, 1, 9, 3, 8, 5];
let target = 7;
let mut index = 0;
let mut found = false;
while index < data.len() && !found {
if data[index] == target {
found = true;
} else {
index += 1;
}
}
if found {
println!("Found {} at index {}", target, index);
} else {
println!("{} not found", target);
}
}

Sorting Algorithms

fn main() {
// Bubble sort with while
let mut arr = [64, 34, 25, 12, 22, 11, 90];
println!("Original: {:?}", arr);
let n = arr.len();
let mut swapped = true;
let mut i = 0;
while swapped {
swapped = false;
i = 0;
while i < n - 1 {
if arr[i] > arr[i + 1] {
arr.swap(i, i + 1);
swapped = true;
}
i += 1;
}
}
println!("Bubble sorted: {:?}", arr);
// Insertion sort with while
let mut arr = [64, 34, 25, 12, 22, 11, 90];
println!("Original: {:?}", arr);
let mut i = 1;
while i < arr.len() {
let key = arr[i];
let mut j = i;
while j > 0 && arr[j - 1] > key {
arr[j] = arr[j - 1];
j -= 1;
}
arr[j] = key;
i += 1;
}
println!("Insertion sorted: {:?}", arr);
// Selection sort with while
let mut arr = [64, 34, 25, 12, 22, 11, 90];
println!("Original: {:?}", arr);
let mut i = 0;
while i < arr.len() - 1 {
let mut min_idx = i;
let mut j = i + 1;
while j < arr.len() {
if arr[j] < arr[min_idx] {
min_idx = j;
}
j += 1;
}
if min_idx != i {
arr.swap(i, min_idx);
}
i += 1;
}
println!("Selection sorted: {:?}", arr);
}

Mathematical Algorithms

fn main() {
// Greatest Common Divisor (GCD) with while
fn gcd(mut a: u64, mut b: u64) -> u64 {
while b != 0 {
let temp = b;
b = a % b;
a = temp;
}
a
}
println!("GCD of 48 and 18: {}", gcd(48, 18));
println!("GCD of 56 and 42: {}", gcd(56, 42));
// Prime number generation
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
}
println!("Primes up to 50:");
let mut n = 2;
while n <= 50 {
if is_prime(n) {
print!("{} ", n);
}
n += 1;
}
println!();
// Factorial
fn factorial(n: u64) -> u64 {
let mut result = 1;
let mut i = 1;
while i <= n {
result *= i;
i += 1;
}
result
}
for i in 0..=10 {
println!("{}! = {}", i, factorial(i));
}
// Fibonacci sequence
fn fibonacci(limit: u64) {
let mut a = 0;
let mut b = 1;
while a <= limit {
print!("{} ", a);
let next = a + b;
a = b;
b = next;
}
println!();
}
println!("Fibonacci up to 100:");
fibonacci(100);
}

9. While Loops in State Machines

Simple State Machine

#[derive(Debug, PartialEq)]
enum TrafficLight {
Red,
Yellow,
Green,
}
impl TrafficLight {
fn next(&self) -> Self {
match self {
TrafficLight::Red => TrafficLight::Green,
TrafficLight::Green => TrafficLight::Yellow,
TrafficLight::Yellow => TrafficLight::Red,
}
}
fn duration(&self) -> u32 {
match self {
TrafficLight::Red => 30,
TrafficLight::Yellow => 5,
TrafficLight::Green => 25,
}
}
}
fn run_traffic_light(cycles: usize) {
let mut state = TrafficLight::Red;
let mut cycle = 0;
while cycle < cycles {
println!("Cycle {}: {:?} for {} seconds", 
cycle + 1, state, state.duration());
// Simulate waiting
std::thread::sleep(std::time::Duration::from_millis(100));
state = state.next();
if state == TrafficLight::Red {
cycle += 1;
}
}
}
// TCP state machine
#[derive(Debug, PartialEq)]
enum TcpState {
Closed,
Listen,
SynSent,
SynReceived,
Established,
FinWait1,
FinWait2,
TimeWait,
CloseWait,
LastAck,
}
impl TcpState {
fn next(&self, event: &str) -> Option<Self> {
match (self, event) {
(TcpState::Closed, "passive_open") => Some(TcpState::Listen),
(TcpState::Closed, "active_open") => Some(TcpState::SynSent),
(TcpState::Listen, "syn") => Some(TcpState::SynReceived),
(TcpState::SynSent, "syn_ack") => Some(TcpState::Established),
(TcpState::SynReceived, "ack") => Some(TcpState::Established),
(TcpState::Established, "close") => Some(TcpState::FinWait1),
(TcpState::FinWait1, "ack") => Some(TcpState::FinWait2),
(TcpState::FinWait1, "fin") => Some(TcpState::Closing),
(TcpState::FinWait2, "fin") => Some(TcpState::TimeWait),
(TcpState::CloseWait, "close") => Some(TcpState::LastAck),
(TcpState::LastAck, "ack") => Some(TcpState::Closed),
(TcpState::TimeWait, "timeout") => Some(TcpState::Closed),
_ => None,
}
}
}
fn main() {
println!("Traffic Light Simulation:");
run_traffic_light(3);
println!("\nTCP State Machine:");
let mut state = TcpState::Closed;
let events = vec!["active_open", "syn_ack", "close", "ack", "fin", "timeout"];
let mut event_iter = events.iter();
println!("Initial state: {:?}", state);
while let Some(event) = event_iter.next() {
if let Some(new_state) = state.next(event) {
println!("Event: {} -> {:?}", event, new_state);
state = new_state;
} else {
println!("Event: {} -> Invalid transition from {:?}", event, state);
break;
}
}
}

10. While Loops in Game Development

Simple Game Loop

use std::io;
use std::time::{Duration, Instant};
use rand::Rng;
struct Game {
player_pos: i32,
enemy_pos: i32,
score: i32,
running: bool,
}
impl Game {
fn new() -> Self {
Game {
player_pos: 0,
enemy_pos: 10,
score: 0,
running: true,
}
}
fn update(&mut self, input: &str) {
match input {
"a" => self.player_pos -= 1,
"d" => self.player_pos += 1,
"q" => self.running = false,
_ => {}
}
// Simple enemy AI
if self.player_pos < self.enemy_pos {
self.enemy_pos -= 1;
} else if self.player_pos > self.enemy_pos {
self.enemy_pos += 1;
}
// Check collision
if self.player_pos == self.enemy_pos {
self.score += 10;
self.enemy_pos = rand::thread_rng().gen_range(0..20);
println!("Enemy caught! Score: {}", self.score);
}
}
fn render(&self) {
for i in 0..20 {
if i == self.player_pos {
print!("P");
} else if i == self.enemy_pos {
print!("E");
} else {
print!(".");
}
}
println!(" Score: {}", self.score);
}
fn run(&mut self) {
let mut last_update = Instant::now();
let frame_time = Duration::from_millis(100);
println!("Game started! Use 'a'/'d' to move, 'q' to quit");
while self.running {
let now = Instant::now();
let dt = now.duration_since(last_update);
if dt >= frame_time {
self.render();
// Get input
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
let input = input.trim();
self.update(input);
last_update = now;
}
}
println!("Game over! Final score: {}", self.score);
}
}
fn main() {
let mut game = Game::new();
game.run();
}

11. Performance Considerations

Loop Optimization

fn main() {
// Prefer while let over manual index checking
let data = vec![1, 2, 3, 4, 5];
// Less efficient (bounds check each iteration)
let mut i = 0;
while i < data.len() {
let _val = data[i]; // Bounds checked
i += 1;
}
// More efficient (iterator, no bounds checks)
let mut iter = data.iter();
while let Some(val) = iter.next() {
let _val = val;
}
// Loop unrolling optimization
let mut sum = 0;
let mut iter = data.iter();
// Manual unrolling for performance (rarely needed)
while let (Some(a), Some(b), Some(c)) = (iter.next(), iter.next(), iter.next()) {
sum += a + b + c;
}
// Handle remaining elements
while let Some(x) = iter.next() {
sum += x;
}
// Benchmark example
use std::time::Instant;
let data: Vec<i32> = (0..1000000).collect();
// While with index
let start = Instant::now();
let mut sum1 = 0;
let mut i = 0;
while i < data.len() {
sum1 += data[i];
i += 1;
}
let time1 = start.elapsed();
// While let with iterator
let start = Instant::now();
let mut sum2 = 0;
let mut iter = data.iter();
while let Some(val) = iter.next() {
sum2 += val;
}
let time2 = start.elapsed();
println!("Index while: {:?}, sum = {}", time1, sum1);
println!("Iterator while: {:?}, sum = {}", time2, sum2);
}

Memory Access Patterns

fn main() {
// Cache-friendly vs cache-unfriendly access
let matrix_size = 1000;
let mut matrix = vec![vec![0; matrix_size]; matrix_size];
// Row-major access (cache-friendly)
let start = std::time::Instant::now();
let mut i = 0;
while i < matrix_size {
let mut j = 0;
while j < matrix_size {
matrix[i][j] += 1;
j += 1;
}
i += 1;
}
println!("Row-major: {:?}", start.elapsed());
// Column-major access (cache-unfriendly)
let start = std::time::Instant::now();
let mut j = 0;
while j < matrix_size {
let mut i = 0;
while i < matrix_size {
matrix[i][j] += 1;
i += 1;
}
j += 1;
}
println!("Column-major: {:?}", start.elapsed());
}

12. Common Patterns and Best Practices

Pattern: Early Exit

fn find_first_even(numbers: &[i32]) -> Option<i32> {
let mut iter = numbers.iter();
while let Some(&num) = iter.next() {
if num % 2 == 0 {
return Some(num);
}
}
None
}
fn validate_input(input: &str) -> bool {
let mut chars = input.chars();
while let Some(c) = chars.next() {
if !c.is_alphanumeric() {
return false;
}
}
!input.is_empty()
}
fn main() {
let numbers = vec![1, 3, 5, 6, 7, 9];
if let Some(first_even) = find_first_even(&numbers) {
println!("First even: {}", first_even);
}
println!("Valid 'hello123': {}", validate_input("hello123"));
println!("Valid 'hello@123': {}", validate_input("hello@123"));
}

Pattern: Accumulator

fn running_sum(numbers: &[i32]) -> Vec<i32> {
let mut result = Vec::with_capacity(numbers.len());
let mut sum = 0;
let mut iter = numbers.iter();
while let Some(&num) = iter.next() {
sum += num;
result.push(sum);
}
result
}
fn running_product(numbers: &[i32]) -> Vec<i32> {
let mut result = Vec::with_capacity(numbers.len());
let mut product = 1;
let mut iter = numbers.iter();
while let Some(&num) = iter.next() {
product *= num;
result.push(product);
}
result
}
fn main() {
let nums = vec![1, 2, 3, 4, 5];
println!("Numbers: {:?}", nums);
println!("Running sum: {:?}", running_sum(&nums));
println!("Running product: {:?}", running_product(&nums));
}

Pattern: 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();
let mut start = 0;
while start + window_size <= numbers.len() {
let window = &numbers[start..start + window_size];
let max = *window.iter().max().unwrap();
result.push(max);
start += 1;
}
result
}
fn moving_average(numbers: &[f64], window_size: usize) -> Vec<f64> {
if numbers.len() < window_size {
return Vec::new();
}
let mut result = Vec::new();
let mut start = 0;
while start + window_size <= numbers.len() {
let window = &numbers[start..start + window_size];
let avg = window.iter().sum::<f64>() / window_size as f64;
result.push(avg);
start += 1;
}
result
}
fn main() {
let numbers = vec![3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5];
println!("Numbers: {:?}", numbers);
println!("Window max (size 3): {:?}", sliding_window_max(&numbers, 3));
let floats = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
println!("Moving average (size 3): {:?}", moving_average(&floats, 3));
}

Conclusion

Rust's while loops provide flexible and safe iteration control:

Key Takeaways

  1. Basic while: while condition { } for condition-based loops
  2. while let: while let pattern = expr { } for pattern matching
  3. Break/Continue: Control flow with labels for nested loops
  4. Collections: Efficient iteration with iterators and while let
  5. Error Handling: Combine with Result and Option for robust code
  6. State Machines: Model complex state transitions
  7. Algorithms: Implement search, sort, and mathematical algorithms

Best Practices

  1. Prefer for loops when iterating over collections
  2. Use while let for pattern-based iteration
  3. Use loop for infinite loops (clearer intent)
  4. Avoid manual indexing when possible
  5. Use labeled breaks for nested loops
  6. Consider early returns to reduce nesting
  7. Keep loop bodies small and focused

Performance Tips

  1. Use iterators instead of index-based while loops
  2. Cache length when using index-based loops
  3. Consider memory access patterns for large data structures
  4. Profile before optimizing - modern compilers are smart
  5. Use while let for Option/Result iteration

While loops in Rust provide the foundation for many algorithms and control flow patterns, working seamlessly with the language's ownership system and type safety guarantees.

Leave a Reply

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


Macro Nepal Helper