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.