Skip to content

add an extract macro which extracts values matched in a pattern #495

Open
@vxpm

Description

Proposal

Problem statement

it's not uncommon to pattern match on a value only to obtain the value of a binding. currently, the only way to do this is to either match on the value, use if let or use let else. all these solutions involve multiple (~3) lines of code for a relatively simple operation, making code less concise.

Motivating examples or use cases

enum Value {
    Int(u64),
    Float(f64),
    Char(char),
}

fn main() {
    use Value::*;
    let arr = [Int(0), Char('a'), Float(0.0), Int(1), Char('b')];

    // notice how this simply filter_map takes 4 whole lines!
    let chars = arr.into_iter().filter_map(|x| match x {
        Char(c) => Some(c),
        _ => None,
    });

    for c in chars {
        println!("got a character: {c}");
    }
}

Solution sketch

i propose an extract macro which extracts values matched in a pattern in a way similar to the matches macro:

macro_rules! extract {
    ($expression:expr, $pattern:pat $(if $guard:expr)? => $extracted:expr $(,)?) => {
        match $expression {
            $pattern $(if $guard)? => Some($extracted),
            _ => None
        }
    };
}

the motivating example would then become:

enum Value {
    Int(u64),
    Float(f64),
    Char(char),
}

fn main() {
    use Value::*;
    let arr = [Int(0), Char('a'), Float(0.0), Int(1), Char('b')];

    // a single line!
    let chars = arr.into_iter().filter_map(|x| extract!(x, Char(c) => c));
    for c in chars {
        println!("got a character: {c}");
    }
}

Alternatives

as an alternative, just keep using match, if let and let else, since they are able to get the job done. however, it's important to notice that they can also do what matches does, but that does not make matches undesirable or any less useful.

Links and related work

searching crates.io for extract macro shows a crate implementing a macro with the exact same proposed syntax, but slightly different implementation.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    T-libs-apiapi-change-proposalA proposal to add or alter unstable APIs in the standard libraries

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions