Concise Rust Pattern Matching with Let-Else

RustRustBeginner
Practice Now

This tutorial is from open-source community. Access the source code

Introduction

In this lab, the use of let-else in Rust is demonstrated, where a refutable pattern can match and bind variables in the surrounding scope, or else diverge when the pattern doesn't match by using statements like break, return, or panic!. This construct allows for concise and readable code when dealing with pattern matching and error handling scenarios, eliminating the need for repeating code blocks or using outer let statements.

Note: If the lab does not specify a file name, you can use any file name you want. For example, you can use main.rs, compile and run it with rustc main.rs && ./main.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("`Rust`")) -.-> rust/BasicConceptsGroup(["`Basic Concepts`"]) rust(("`Rust`")) -.-> rust/DataTypesGroup(["`Data Types`"]) rust(("`Rust`")) -.-> rust/FunctionsandClosuresGroup(["`Functions and Closures`"]) rust(("`Rust`")) -.-> rust/MemorySafetyandManagementGroup(["`Memory Safety and Management`"]) rust(("`Rust`")) -.-> rust/DataStructuresandEnumsGroup(["`Data Structures and Enums`"]) rust(("`Rust`")) -.-> rust/ErrorHandlingandDebuggingGroup(["`Error Handling and Debugging`"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("`Variable Declarations`") rust/BasicConceptsGroup -.-> rust/mutable_variables("`Mutable Variables`") rust/BasicConceptsGroup -.-> rust/shadowing("`Variable Shadowing`") rust/DataTypesGroup -.-> rust/integer_types("`Integer Types`") rust/DataTypesGroup -.-> rust/string_type("`String Type`") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("`Function Syntax`") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("`Expressions and Statements`") rust/MemorySafetyandManagementGroup -.-> rust/lifetime_specifiers("`Lifetime Specifiers`") rust/DataStructuresandEnumsGroup -.-> rust/method_syntax("`Method Syntax`") rust/ErrorHandlingandDebuggingGroup -.-> rust/panic_usage("`panic! Usage`") subgraph Lab Skills rust/variable_declarations -.-> lab-99318{{"`Concise Rust Pattern Matching with Let-Else`"}} rust/mutable_variables -.-> lab-99318{{"`Concise Rust Pattern Matching with Let-Else`"}} rust/shadowing -.-> lab-99318{{"`Concise Rust Pattern Matching with Let-Else`"}} rust/integer_types -.-> lab-99318{{"`Concise Rust Pattern Matching with Let-Else`"}} rust/string_type -.-> lab-99318{{"`Concise Rust Pattern Matching with Let-Else`"}} rust/function_syntax -.-> lab-99318{{"`Concise Rust Pattern Matching with Let-Else`"}} rust/expressions_statements -.-> lab-99318{{"`Concise Rust Pattern Matching with Let-Else`"}} rust/lifetime_specifiers -.-> lab-99318{{"`Concise Rust Pattern Matching with Let-Else`"}} rust/method_syntax -.-> lab-99318{{"`Concise Rust Pattern Matching with Let-Else`"}} rust/panic_usage -.-> lab-99318{{"`Concise Rust Pattern Matching with Let-Else`"}} end

let-else

With let-else, a refutable pattern can match and bind variables in the surrounding scope like a normal let, or else diverge (e.g. break, return, panic!) when the pattern doesn't match.

use std::str::FromStr;

fn get_count_item(s: &str) -> (u64, &str) {
    let mut it = s.split(' ');
    let (Some(count_str), Some(item)) = (it.next(), it.next()) else {
        panic!("Can't segment count item pair: '{s}'");
    };
    let Ok(count) = u64::from_str(count_str) else {
        panic!("Can't parse integer: '{count_str}'");
    };
    (count, item)
}

fn main() {
    assert_eq!(get_count_item("3 chairs"), (3, "chairs"));
}

The scope of name bindings is the main thing that makes this different from match or if let-else expressions. You could previously approximate these patterns with an unfortunate bit of repetition and an outer let:

use std::str::FromStr;

fn get_count_item(s: &str) -> (u64, &str) {
    let mut it = s.split(' ');
    let (count_str, item) = match (it.next(), it.next()) {
        (Some(count_str), Some(item)) => (count_str, item),
        _ => panic!("Can't segment count item pair: '{s}'"),
    };
    let count = if let Ok(count) = u64::from_str(count_str) {
        count
    } else {
        panic!("Can't parse integer: '{count_str}'");
    };
        (count, item)
    }

    assert_eq!(get_count_item("3 chairs"), (3, "chairs"));

Summary

Congratulations! You have completed the Let-Else lab. You can practice more labs in LabEx to improve your skills.

Other Rust Tutorials you may like