Search code examples
rusttuplesrust-macros

Indexing a tuple using a macro in Rust unexpected token


I am trying to create a macro to perform a certain action for every element in a tuple in order to compensate for not being able to iterate over them.

I wrote some code that replicates my issue:

fn main() {
    let tuple = (1, 2);

    macro_rules! index_tuple {
        ($($i:literal),+) => {
            $(
                let t$i = tuple.$i;
            )+
        }
    }
    
    index_tuple!(0, 1);
}

Rust playground link


But I have been met with the following error:

error: expected one of `:`, `;`, `=`, `@`, or `|`, found `0`

I have tried expanding the macro with CLion and the expanded macro worked perfectly fine so I am uncertain whether it is my fault or not.


Solution

  • Rust macros aren't simple text manipulation. So what your macro currently does is produce the tokens 'let' 't' '0' '=' 'tuple' '.' '0' if you want to join them you have to use quote! which is notoriously underpowered and can't create new identifiers so it doesn't work here or paste::paste!:

    use paste::paste;
    fn main() {
        let tuple = (1, 2);
    
        macro_rules! index_tuple {
            ($($i:literal),+) => { paste!{
                $(
                    let [<t $i>] = tuple.$i;
                )+
            }}
        }
    
        index_tuple!(0, 1);
    }
    

    Then you run into the next problem because of macro hygiene identifiers defined in declarative macros can't be accessed from outside the macro. Or in other words t0 and t1 will be as undefined after the macro as they are before. So your macro seems rather pointless, but maybe that's just from minimalizing it.