21.14 The let else
Construct (Rust 1.65+)
let else
allows a refutable pattern in a let
binding. If the pattern matches, variables are bound and available in the surrounding scope. If the pattern fails, the else
block is executed. Crucially, the else
block must diverge (e.g., using return
, break
, continue
, panic!
), ensuring control flow doesn’t implicitly continue after a failed match.
fn get_config_param(param_name: &str) -> Option<String> { match param_name { "port" => Some("8080".to_string()), _ => None, } } fn setup_server() -> Result<(), String> { println!("Setting up server..."); // Use let else to ensure 'port_str' is available or diverge let Some(port_str) = get_config_param("port") else { // This block executes if get_config_param returns None eprintln!("Error: Configuration parameter 'port' not found."); return Err("Missing configuration".to_string()); // Diverge by returning Err }; // If we reach here, `port_str` is bound and available let port: u16 = port_str.parse().map_err(|_| "Invalid port format".to_string())?; println!("Using port: {}", port); // ... continue setup with port ... Ok(()) } fn main() { match setup_server() { Ok(_) => println!("Server setup successful."), Err(e) => println!("Server setup failed: {}", e), } }
let else
is excellent for early returns or handling errors/missing values concisely at the start of functions or blocks, avoiding deeper nesting than if let
or match
.