Там несколько вещей не так с вашим синтаксисом.Если вы хотите сопоставить повторяющийся шаблон, вам нужно начать группировку с $
, например: $($matcher:tt => $result:tt),*
.
Далее вы, вероятно, захотите сопоставить больше, чем идентификаторы, поскольку любое выражение допустимо для сопоставления, поэтому измените его на expr
.Слева от =>
вам понадобится pat
(шаблон), а не tt
.Дерево токенов является общим, но, например, в n if n < 5
будет соответствовать 5 отдельным токенам - n
, if
, n
, <
, 5
- и вы, как правило, отступаете от этого только тогда, когда ничегоеще работает.То же самое для результата - это должно быть expr
(выражение).
Игнорируя охрану if < 5
, вы можете сопоставить следующее:
my_match! {
x,
10 => "Ten",
_ => "something else"
}
со следующиммакрос:
macro_rules! my_match {
($obj:expr, $($matcher:pat => $result:expr),*) => {
match $obj {
$($matcher => $result),*
}
}
}
Охранники раздражают, потому что они необязательны, но квантификатор ?
еще не стабилен.Вместо этого вы должны использовать *
(0 или больше), даже если это будет технически соответствовать больше, чем вам нужно.
Полный макрос имеет следующий вид:
macro_rules! my_match {
($obj:expr, $($matcher:pat $(if $pred:expr)* => $result:expr),*) => {
match $obj {
$($matcher $(if $pred)* => $result),*
}
}
}
и поддерживает это использование:
let x = 7;
let s = my_match! {
x,
10 => "Ten",
n if x < 5 => "Less than 5",
_ => "something else"
};
println!("s = {:?}", s); // "Something else"
Блок также является expr
, так что это также допустимо:
my_match! {
x,
10 => "Ten",
n if x < 5 => {
println!("it was {}", n);
"Less than 5"
},
_ => "something else"
};