我需要获取宏重复元素的索引来编写下一个代码:
struct A {
data: [i32; 3]
}
macro_rules! tst {
( $( $n:ident ),* ) => {
impl A {
$(
fn $n(self) -> i32 {
self.data[?] // here I need the index
}
)*
}
}
}
我知道一种方法:只需告诉用户用手写索引:
( $( $i:ident => $n:ident ),* )
但是有没有更优雅的方式不需要用户操作?
最简单的方法是使用递归,如下所示:
struct A {
data: [i32; 3]
}
macro_rules! tst {
(@step $_idx:expr,) => {};
(@step $idx:expr, $head:ident, $($tail:ident,)*) => {
impl A {
fn $head(&self) -> i32 {
self.data[$idx]
}
}
tst!(@step $idx + 1usize, $($tail,)*);
};
($($n:ident),*) => {
tst!(@step 0usize, $($n,)*);
}
}
tst!(one, two, three);
fn main() {
let a = A { data: [10, 20, 30] };
println!("{:?}", (a.one(), a.two(), a.three()));
}
请注意,我更改了方法以采用
&self
而不是 self
,因为这样可以更轻松地在 main
函数中编写示例。 :)
递归中的每一步只是将索引加 1。使用“类型化”整数文字是一个好主意,以避免由于大量整数推断而导致编译速度减慢。
希望当RFC:声明性宏元变量表达式#3086完全实现时,这最终将变得可用。现在您必须启用
macro_metavar_expr
:
#![feature(macro_metavar_expr)]
macro_rules! tst {
( $( $n:ident ),* ) => {
impl A {
$(
fn $n(self) -> i32 {
self.data[${index()}]
}
)*
}
}
}
tst!(x, y, z);