是否可以创建一个宏来计算扩展项目的数量?
Is it possible to create a macro which counts the number of expanded items?
是否可以创建一个计算展开项目数的宏?
macro_rules! count {
($($name:ident),*) => {
pub enum Count {
$(
$name = 1 << $i // $i is the current expansion index
),*
}
}
}
count!(A, B, C);
在这种情况下,不。宏可以创建一个表达式来计算传递给它的标识符的数量,但它只会在运行时进行评估。我在短短几分钟内创建了 this example,但我意识到它对您正在做的事情不起作用。
然而,Compiler plugins特别适合这类工作。虽然它们实施起来并不简单,但我认为为此目的创建一个不会太困难。也许看一看,试试看,如果卡住了再回来?
是的,如果您将其打包为 idents 数组:
macro_rules! count {
($($name:ident),*) => {
{
let counter = [$(stringify!($name),)*];
counter.len()
}
}
}
可以使用计数、名称、名称的倒序。之后,你可以用它来构建一些东西。对于 enum
建筑,您必须使用 this.
之类的东西加入它
这是一个计算匹配项数量的宏:
macro_rules! count_items {
($name:ident) => { 1 };
($first:ident, $($rest:ident),*) => {
1 + count_items!($($rest),*)
}
}
fn main() {
const X: usize = count_items!(a);
const Y: usize = count_items!(a, b);
const Z: usize = count_items!(a, b, c);
assert_eq!(1, X);
assert_eq!(2, Y);
assert_eq!(3, Z);
}
请注意,计数是在编译时计算的。
对于您的示例,您可以使用 accumulation:
macro_rules! count {
($first:ident, $($rest:ident),*) => (
count!($($rest),+ ; 0; $first = 0)
);
($cur:ident, $($rest:ident),* ; $last_index: expr ; $($var:ident = $index:expr)+) => (
count!($($rest),* ; $last_index + 1; $($var = $index)* $cur = $last_index + 1)
);
($cur:ident; $last_index:expr ; $($var:ident = $index:expr)+) => (
#[repr(C)]
enum Count {
$($var = 1 << $index),*,
$cur = 1 << ($last_index + 1),
}
);
}
pub fn main() {
count!(A, B, C, D);
assert_eq!(1, Count::A as usize);
assert_eq!(2, Count::B as usize);
assert_eq!(4, Count::C as usize);
assert_eq!(8, Count::D as usize);
}
由于这个问题很笼统,所以张贴一个计算参数由 white-space(不是逗号)分隔的例子。
虽然回想起来很明显,但我花了一段时间才弄明白:
/// Separated by white-space.
#[macro_export]
macro_rules! count_args_space {
($name:ident) => { 1 };
($first:ident $($rest:ident) *) => {
1 + count_args_space!($($rest) *)
}
}
/// Separated by commas.
#[macro_export]
macro_rules! count_args_comma {
($name:ident) => { 1 };
($first:ident, $($rest:ident),*) => {
1 + count_args_comma!($($rest),*)
}
}
第二个例子来自@malbarbo,只是发布到所以你可以看到所需的 2x 更改。
是否可以创建一个计算展开项目数的宏?
macro_rules! count {
($($name:ident),*) => {
pub enum Count {
$(
$name = 1 << $i // $i is the current expansion index
),*
}
}
}
count!(A, B, C);
在这种情况下,不。宏可以创建一个表达式来计算传递给它的标识符的数量,但它只会在运行时进行评估。我在短短几分钟内创建了 this example,但我意识到它对您正在做的事情不起作用。
然而,Compiler plugins特别适合这类工作。虽然它们实施起来并不简单,但我认为为此目的创建一个不会太困难。也许看一看,试试看,如果卡住了再回来?
是的,如果您将其打包为 idents 数组:
macro_rules! count {
($($name:ident),*) => {
{
let counter = [$(stringify!($name),)*];
counter.len()
}
}
}
可以使用计数、名称、名称的倒序。之后,你可以用它来构建一些东西。对于 enum
建筑,您必须使用 this.
这是一个计算匹配项数量的宏:
macro_rules! count_items {
($name:ident) => { 1 };
($first:ident, $($rest:ident),*) => {
1 + count_items!($($rest),*)
}
}
fn main() {
const X: usize = count_items!(a);
const Y: usize = count_items!(a, b);
const Z: usize = count_items!(a, b, c);
assert_eq!(1, X);
assert_eq!(2, Y);
assert_eq!(3, Z);
}
请注意,计数是在编译时计算的。
对于您的示例,您可以使用 accumulation:
macro_rules! count {
($first:ident, $($rest:ident),*) => (
count!($($rest),+ ; 0; $first = 0)
);
($cur:ident, $($rest:ident),* ; $last_index: expr ; $($var:ident = $index:expr)+) => (
count!($($rest),* ; $last_index + 1; $($var = $index)* $cur = $last_index + 1)
);
($cur:ident; $last_index:expr ; $($var:ident = $index:expr)+) => (
#[repr(C)]
enum Count {
$($var = 1 << $index),*,
$cur = 1 << ($last_index + 1),
}
);
}
pub fn main() {
count!(A, B, C, D);
assert_eq!(1, Count::A as usize);
assert_eq!(2, Count::B as usize);
assert_eq!(4, Count::C as usize);
assert_eq!(8, Count::D as usize);
}
由于这个问题很笼统,所以张贴一个计算参数由 white-space(不是逗号)分隔的例子。
虽然回想起来很明显,但我花了一段时间才弄明白:
/// Separated by white-space.
#[macro_export]
macro_rules! count_args_space {
($name:ident) => { 1 };
($first:ident $($rest:ident) *) => {
1 + count_args_space!($($rest) *)
}
}
/// Separated by commas.
#[macro_export]
macro_rules! count_args_comma {
($name:ident) => { 1 };
($first:ident, $($rest:ident),*) => {
1 + count_args_comma!($($rest),*)
}
}
第二个例子来自@malbarbo,只是发布到所以你可以看到所需的 2x 更改。