2

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

Playground

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?

1 Answer 1

8

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 {}
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.