有没有办法在这样的宏中提取 struct 字段的"索引"(出现的顺序):

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宏可以做到这一点(并不是我知道如何编写),但是使用声明性宏能做到这一点吗?

推荐答案

在晚上,这很容易做到,使用#![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()}),
                );)*
            }
        }
    }
}

在马厩上,你可以用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, )*
        }
    };
}

Rust相关问答推荐

Rust kill std::processs::child

在HashMap中插入Vacant条目的可变借位问题

是否可以为`T:Copy`执行`T. clone`的测试

交叉术语未正确清除屏幕

为什么我不能从带有字符串的 struct 的引用迭代器中收集VEC<;&;str&>?

如何获取Serde struct 的默认实例

将PathBuf转换为字符串

为什么Deref类特征不构成?

Rust移动/复制涉及实际复制时进行检测

Rust ndarray:如何从索引中 Select 数组的行

try 实现线程安全的缓存

如何使用tracing-subscriberRust crate 构建多编写者、全局过滤订阅者

更新 rust ndarray 中矩阵的一行

Rust并发读写引起的死锁问题

通过mem::transmute将数组展平安全吗?

max(ctz(x), ctz(y)) 有更快的算法吗?

&self 参数在 trait 的功能中是必需的吗?

我如何将特征作为 struct 的拥有字段?

为实现特征的所有类型实现显示

当特征函数依赖于为 Self 实现的通用标记特征时实现通用包装器