Reputation: 222108
I'm trying to make a macro that would let me iterate through a list of types to reduce trait impl boilerplate. (I'm currently using a different macro based solution, but this seems more readable, if it's possible without adding a dependency.)
This is the syntax I am aiming for:
trait MyTrait {}
tfor! {
for Ty in [i32, u32] {
impl MyTrait for Ty {}
}
}
My attempt:
macro_rules! tfor {
(for $ty:ident in [$($typ:ident),*] $tt:tt) => {
$(
type $ty = $typ;
tfor! { @extract $tt }
)*
};
(@extract { $($tt:tt)* }) => {
$($tt)*
};
}
This generates an error as both the iterations define a type named Ty
in the same scope:
|
4 | type $ty = $typ;
| ^^^^^^^^^^^^^^^^
| |
| `Ty` redefined here
| previous definition of the type `Ty` here
Is there a way around this? Can I somehow generate a random identifier in place of Ty
so that this compiles, without using a proc macro or a dependency?
Upvotes: 2
Views: 554
Reputation: 2583
You can scope the trait implementation inside a const
declaration. That way you can re-use the Ty
name without causing conflicts.
macro_rules! tfor {
(for $ty:ident in [$($typ:ident),*] $tt:tt) => {
$(
const _: () = {
type $ty = $typ;
tfor! { @extract $tt }
};
)*
};
(@extract { $($tt:tt)* }) => {
$($tt)*
};
}
trait MyTrait {}
tfor! {
for Ty in [i32, u32] {
impl MyTrait for Ty {}
}
}
Upvotes: 8