21.13 if let and while let: Concise Conditional Matching
When you only care about matching one specific pattern and ignoring the rest, a full match can be verbose. if let and while let provide more concise alternatives.
21.13.1 if let
Handles a single refutable pattern. Executes the block if the pattern matches. Can optionally have an else block for the non-matching case.
fn main() {
let config_value: Option<i32> = Some(5);
// Using if let
if let Some(value) = config_value {
println!("Config value is: {}", value);
} else {
println!("Config value not set.");
}
let error_code: Result<u32, &str> = Err("Network Error");
if let Ok(data) = error_code {
// This block is skipped
println!("Operation succeeded: {}", data);
} else {
println!("Operation failed."); // This block runs
}
}
21.13.2 while let
Creates a loop that continues as long as the pattern matches the value produced in each iteration (commonly from an iterator or repeated function call).
fn main() {
let mut tasks = vec![Some("Task 1"), None, Some("Task 2"), Some("Task 3")];
// Process tasks from the end using pop() which returns Option<T>
while let Some(task_option) = tasks.pop() { // Pattern: Some(task_option)
if let Some(task_name) = task_option { // Nested Pattern: Some(task_name)
println!("Processing: {}", task_name);
} else {
println!("Skipping empty task slot.");
}
}
println!("Finished processing tasks.");
// Example output order: Task 3, Task 2, Skipping empty task slot, Task 1
// More direct with `while let Some(Some(..))` pattern:
let mut data_stream = vec![Some(10), Some(20), None, Some(30)].into_iter();
// The loop runs as long as `next()` returns `Some(Some(value))`
while let Some(Some(value)) = data_stream.next() {
println!("Received value: {}", value); // Outputs 10, 20, 30
}
println!("End of stream.");
}