As of Rust 1.0, there is no way to group multiple patterns into one binding:
// It does not compile
match x as char {
b @ ('A' | 'Z') => println!("A or Z: {}", b),
_ => println!("Try again")
}
// Correct version
match x as char {
b @ 'A' | b @ 'Z' => println!("A or Z: {}", b),
_ => println!("Try again")
}
I was wondering if a macro could do the dirty job of binding all the different possibilities. Here is a partial attempt:
macro_rules! bind_alternatives {
($x:ident, $e:expr) => ($x @ $e);
($x:ident, $e1:expr, $e2:expr) => (
$x @ $e1 | $x @ $e2
);
}
fn main() {
let x = 'a';
match x {
bind_alternatives!(z, 'a', 'c') => println!("Matched"),
_ => println!("No luck")
};
}
This does not compile:
example.rs:4:18: 4:19 error: macro expansion ignores token `|` and any following
example.rs:4 $x @ $e1 | $x @ $e2
^
example.rs:12:9: 12:40 note: caused by the macro expansion here; the usage of `bind_alternatives` is likely invalid in this context
example.rs:12 bind_alternatives!(z, 'a', 'c') => println!("Matched"),
I understand that macros can be expanded into patterns, and the first brace of bind_alternatives
does work. Is it possible to generalize to more than 1 possibility? If not, what prevents it?
A macro is able to expand to things like patterns, expressions and items, but not everything; specifically, macros expand to complete AST nodes, but what you’re dealing with here is not a complete AST node.
Each branch of a match
expression can have one or more patterns, separated by pipes, and an optional pattern guard (if condition
). This is all special match
-specific syntax, and thus not a complete AST node, and thus not something that a macro can expand to.
The parser is looking for a pattern at that point of its parsing, so it expands the macro as a pattern, which concludes before the |
, which doesn’t fit in a pattern grammar. The macro has thus produced more than can be consumed, and the rest is discarded with an error.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With