定义编号实现的一种方法是使用递归宏。 counting arguments 可以创建一个唯一编号,在这种情况下计算尾随参数。
问题在于,第一个结构的数字最大,最后一个结构为零。
如果你只需要数字是唯一的,那没关系,但是在这种情况下,我希望每个结构索引都匹配它传递给宏的顺序。
可以使用递归宏 see this example 反转输入参数。
使用此宏,可以编写通用宏:
apply_args_reverse!(macro_name, arg1 arg2 arg3)
扩展为:
macro_name!(arg3 arg2 arg1)
当然,这本身并不是很有用,但如果参数不是直接写入,而是作为参数传递,它会很有用。
这可用于创建一个宏,该宏以每个参数的数量进行扩展,如下所示:
struct Foo {_var: bool}
struct Bar {_var: u8}
struct Baz {_var: i16}
trait NumberStruct {
fn struct_number() -> usize;
}
macro_rules! count_args_space {
() => {0_usize};
($_head:tt $($tail:tt)*) => {1_usize + count_args_space!($($tail)*)};
}
macro_rules! number_structs_impl {
(@single $t:tt $($tail:tt)*) => (
impl NumberStruct for $t {
fn struct_number() -> usize {
return count_args_space!($($tail)*);
}
}
);
() => {};
($head:tt $($tail:tt)*) => {
number_structs_impl!(@single $head $($tail)*);
number_structs_impl!($($tail)*);
};
}
macro_rules! apply_args_reverse {
($macro_id:tt [] $($reversed:tt)*) => {
$macro_id!($($reversed) *);
};
($macro_id:tt [$first:tt $($rest:tt)*] $($reversed:tt)*) => {
apply_args_reverse!($macro_id [$($rest)*] $first $($reversed)*);
};
// Entry point, use brackets to recursively reverse above.
($macro_id:tt, $($t:tt)*) => {
apply_args_reverse!($macro_id [ $($t)* ]);
};
}
// Note that both commands below work, and can be swapped to reverse argument order.
// number_structs_impl!(Foo Bar Baz);
apply_args_reverse!(number_structs_impl, Foo Bar Baz);
fn main() {
// see if the numbers are correct
macro_rules! print_numbers {
($($t:tt)*) => ($(
print!("{}:{} ", stringify!($t), $t::struct_number());
)*)
}
print_numbers!(Baz Bar Foo);
println!();
}
注意以下陈述:
number_structs_impl!(Foo Bar Baz);
...和
apply_args_reverse!(number_structs_impl, Foo Bar Baz);
... 是可互换的,被注释的交换会颠倒分配给每个结构的数字顺序。
注意:保留我的other answer,虽然这更简洁,但它也更脆弱,容易出现难以解决的问题,因为宏扩展嵌套很深(我在让它工作时发现了这一点至少)。