add an extract
macro which extracts values matched in a pattern #495
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