rust 在结构生成宏中提取字段的匹配项索引

x0fgdtte  于 2023-01-21  发布在  其他
关注(0)|答案(1)|浏览(123)

有没有办法像这样提取宏中结构域的“索引”(出现的顺序):

macro_rules! example {
    (struct $name:ident {
        $($field_name:ident: $field_type:ty,)*
    }) => {
        struct $name {
            $($field_name: $field_type,)*
        }
        impl $name {
            fn print_members(&self) {
                $(println!("{} {} {}",
                    stringify!($field_name),
                    stringify!($field_type),
                    stringify!(<<<FIELD INDEX SOMEHOW>>>),
                );)*
            }
        }
    }
}

使得

example! {
    struct SomeStruct {
        a: String,
        b: String,
        c: usize,
    }
}

将打印:

a String 0
b String 1
c usize 2

我非常肯定proc宏可以做到这一点(虽然我不知道如何编写),但声明性宏是否可以做到这一点?

vlju58qv

vlju58qv1#

在夜间,使用#![feature(macro_metavar_expr)]很容易做到这一点:

#![feature(macro_metavar_expr)]

macro_rules! example {
    (struct $name:ident {
        $($field_name:ident: $field_type:ty,)*
    }) => {
        struct $name {
            $($field_name: $field_type,)*
        }
        impl $name {
            fn print_members(&self) {
                $(println!("{} {} {}",
                    stringify!($field_name),
                    stringify!($field_type),
                    stringify!(${index()}),
                );)*
            }
        }
    }
}

在stable上,你可以使用TT咀嚼来计数。但是你不能再使用stringify!(),因为这将创建一个未展开的序列0 + 1 + 1 + 1 + ...。因为你只是在打印,所以你可以直接使用这个数字:

macro_rules! example {
    (struct $name:ident {
        $($field_name:ident: $field_type:ty,)*
    }) => {
        struct $name {
            $($field_name: $field_type,)*
        }
        impl $name {
            fn print_members(&self) {
                example! { @generate_println
                    [ 0 ]
                    $( $field_name : $field_type, )*
                }
            }
        }
    };
    
    { @generate_println
        [ $index:expr ]
    } => {
        // Stop condition.
    };
    { @generate_println
        [ $index:expr ]
        $first_field_name:ident : $first_field_type:ty,
        $( $rest_field_name:ident : $rest_field_type:ty, )*
    } => {
        println!("{} {} {}",
            stringify!($first_field_name),
            stringify!($first_field_type),
            $index,
        );
        example! { @generate_println
            [ $index + 1 ]
            $( $rest_field_name : $rest_field_type, )*
        }
    };
}

相关问题