Мы можем начать с написания макроса, который принимает любое количество аргументов:
macro_rules! match_token_patten {
($parser:ident, $($arg:ident),*)) => {{
/* macro body */
}};
}
$($arg:ident),*
будет захватывать любые числовые идентификаторы, разделенные запятыми.
Далее нам нужно вычислить результаты для каждого метода. Простой способ сделать это - просто сохранить их в кортеже, например, (parser.a(), parser.b(), parser.c())
. Мы будем использовать синтаксис $( ... ),*
снова, чтобы расширить захваченные переменные аргументы:
macro_rules! match_token_patten {
($parser:ident, $($arg:ident),*)) => {{
let results = ( $( $parser.$arg() ),* );
}};
}
Теперь мы хотим превратить (Some(x), Some(y), ...)
в Some((x, y, ...))
. Мы можем использовать сопоставление с образцом для этого! Мы можем написать это как:
if let (Some(a), Some(b), Some(c)) = results {
// only if results is a tuple of three Some values
Some((a, b, c)
} else {
// at least one of the results is None
None
}
Наконец, записав это в форме макроса variadic, мы получим:
macro_rules! match_token_pattern {
($parser:ident, $($a:ident),*) => {{
let results = ( $($parser.$a()),* );
if let ( $(Some($a)),* ) = results {
Some( ( $($a),* ) )
} else {
None
}
}};
}