rust - 如何为特征的每个实现自动生成递增的数字标识符?

标签 rust rust-macros

我有一个 Component 特征,它有一个返回索引的方法,如下所示:

trait Component {
    fn index(&self) -> usize;
}

这些索引用于在位集中设置标志。例如,返回索引 5 的 Component 特征对象将导致在容器中设置第 5 位。

目前我手动为每个实现类型返回一个运行索引:

struct Foo;
struct Bar;

impl Component for Foo {
    fn index(&self) -> usize { 0 }
}

impl Component for Bar {
    fn index(&self) -> usize { 1 }
}

trait 对象被插入到容器中,该容器使用位集跟踪添加的组件:

struct Container<'a> {
    components: Vec<Component + 'a>,
    bits: BitSet
}

impl<'a> Container<'a> {
    fn add<T: Component + 'a>(&mut self, component: T) {
        self.components.push(component);
        self.bits.set(component.index());
    }
}

这很好用,但是手动返回每个实现类型的索引很麻烦。我怎样才能使每个实现类型都自动获取其索引?

最佳答案

你可以定义一个递归调用自身的宏:

macro_rules! impl_component {
    // Empty case to end the recursion
    ($n:expr ;) => {};
    // Match the current count, the current type, and whatever else comes after
    ($n:expr ; $t:ty $(, $rest:tt)*) => {
        impl Component for $t {
            fn index(&self) -> usize { $n }
        }
        // Recurse, incrementing counter and only passing the remaining params
        impl_component!($n + 1; $($rest),*);
    };
    // For the first recursion, set the counter initial value to zero
    ($($types:tt),+) => { impl_component!(0; $($types),*); };
}

impl_component!(Foo, Bar, Baz);

生成的代码将包括这样的实现:

impl Component for Baz {
    fn index(&self) -> usize { 0 + 1 + 1 }
}

编译器会将这些表达式折叠成文字,因此结果等同于您想要的结果。

关于rust - 如何为特征的每个实现自动生成递增的数字标识符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51577597/

相关文章:

rust - 我的变量的生命周期是否由于添加了明显不相关的指令而发生变化?

rust - 如何使用一系列参数初始化结构

rust - 如何创建将输入转换为元组的宏?

rust - 为什么我不能将捕获的 token 传递给嵌套宏?

data-structures - 如何在安全的Rust中遍历相互递归的图?

rust - 如何从 std::cmp::Reverse::<T> 获取 T 值

rust - 在参数位置使用 `impl<T> From<T> for Option<T>` 是惯用的吗?

rust - 是否不可能对使用智能指针(如 Box、Rc 或 Arc)的递归数据类型进行嵌套匹配?

rust - 无法在宏中使用自身,因为宏扩展忽略了标记 `self`

macros - 如何实现 Lispian cond 宏?