Подход к определению нумерованных реализаций заключается в использовании рекурсивного макроса. Уникальный номер может быть создан counting arguments, в этом случае подсчет возвращающих аргументов.
Проблема с этим: индексы меняются на противоположные, где первая структура имеет наибольшее число, последняя структура равна нулю.
Если вам нужны только номера, чтобы быть уникальными, это не имеет значения, однако в этом случае я хочу, чтобы каждый индекс structs соответствовал порядку его передачи макросу.
Входные аргументы могут быть изменены с помощью рекурсивного макроса, 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, в то время как это более кратким, но она более хрупкая, склонная к труднодоступные устранения проблем, так как макрос расширения становится глубоко вложенным (я нашел это при получении его на работу в наименее).