Reputation: 3057
I have something like this in mind:
macro_rules! mymatch {
($obj:ident, ($matcher:tt => $result:tt),*) => {
match $obj {
$matcher
},
}
}
mymatch! {
x,
10 => "Ten",
n if n < 5 => "Less than 5"
}
I don't want to reimplement the match
statement, but I do want to put additional stuff on either side. However, I can't work out how to match
the contents of a match statement.
Upvotes: 5
Views: 5551
Reputation: 58715
There a few things wrong with your syntax. If you want to match a repeated pattern then you need to start the grouping with a $
, like this: $($matcher:tt => $result:tt),*
.
Next, you'll likely want to match more than identifiers, since any expression is valid to match against, so change that to expr
. Left of the =>
you will want a pat
(pattern), not a tt
. A token tree is general, but for example, in n if n < 5
will match 5 separate tokens - n
, if
, n
, <
, 5
- and you generally only fall back on that when nothing else works. The same for result - this should be an expr
(expression) too.
Ignoring the if < 5
guard for now, you can match the following:
my_match! {
x,
10 => "Ten",
_ => "something else"
}
with the following macro:
macro_rules! my_match {
($obj:expr, $($matcher:pat => $result:expr),*) => {
match $obj {
$($matcher => $result),*
}
}
}
The guards are annoying because they are optional, but the ?
quantifier is not yet stable. Instead you have to use *
(0 or more), even though it will technically match more than you need it to.
The full macro is then:
macro_rules! my_match {
($obj:expr, $($matcher:pat $(if $pred:expr)* => $result:expr),*) => {
match $obj {
$($matcher $(if $pred)* => $result),*
}
}
}
And supports the this usage:
let x = 7;
let s = my_match! {
x,
10 => "Ten",
n if x < 5 => "Less than 5",
_ => "something else"
};
println!("s = {:?}", s); // "Something else"
A block is also an expr
, so this is also valid:
my_match! {
x,
10 => "Ten",
n if x < 5 => {
println!("it was {}", n);
"Less than 5"
},
_ => "something else"
};
Upvotes: 6