expr
is an expression token tree, which clearly doesn’t fit in the locations you have tried to place it. Remember that Rust macros are strongly typed: only the types of token trees expected at a given location are permitted.
You’ll need to use sequence repetition ($(…)*
et al.) of ident
to achieve this:
macro_rules! trait_alias {
($name:ident = $base1:ident + $($base2:ident +)+) => {
trait $name: $base1 $(+ $base2)+ { }
impl<T: $base1 $(+ $base2)+> $name for T { }
};
}
trait Foo { }
trait Bar { }
trait_alias!(Alias = Foo + Bar +);
(You can’t have the nicer $base1:ident $(+ $base2:ident)+
or $($base:ident)++
at present for technical reasons.)
There is, however, a technique for cheating, making the macro parser accept things that it would not otherwise: passing them through another macro and forcing it to reinterpret the token trees as a different type. This can be used to good effect here:
macro_rules! items {
($($item:item)*) => ($($item)*);
}
macro_rules! trait_alias {
($name:ident = $($base:tt)+) => {
items! {
trait $name: $($base)+ { }
impl<T: $($base)+> $name for T { }
}
};
}
trait Foo {}
trait Bar {}
trait_alias!(Alias = Foo + Bar);
Note, however, that it will shift syntax checking inside the macro, which is less optimal.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…