在[expr *],path [tt *]和ident [tt *]分支之后匹配单个expr的宏

时间:2016-03-23 11:12:15

标签: macros rust

我试图制作一个我可以通过以下方式调用的宏:

mactest!(some::Path[1, 2, AnotherName[3, 4]])

这相当于以下内容:

make_result(
    "some::Path", 
    1.convert(), 
    2.convert(), 
    make_result(
        "AnotherName", 
        3.convert(), 
        4.convert()
    )
)

其中convert是将为一堆类型实现的某些特征。 (convertmake_result具有相同的结果类型。)

就我而言:

// Note: u32 is used as an example result type. 
// The real code attempts to create a more complicated object.

trait Foo {
    fn convert(&self) -> u32;
}

fn make_result(name: &str, data: Vec<u32>) -> u32 {
    // This example ignores name and makes a meaningless result
    data.iter().fold(0,|a, &b| a + b)
}


#[macro_export]
macro_rules! mactest {
    ( [ $($inner:expr),* ] ) => {{
        let mut result = Vec::new();
        $(
            // Process each element.
            result.push(mactest!($inner));
        )*
        result
    }};
    ($name:path [ $($inner:tt),* ] ) => {
        make_result(stringify!($name), mactest!([$($inner),*]))
    };
    ($name:ident [ $($inner:tt),* ] ) => {
        make_result(stringify!($name), mactest!([$($inner),*]))
    };
    // Process single value. This is never matched?
    ($x:expr) => {
        $x.convert()
    };
}

宏的第一个匹配分支应该与列表中的每个元素匹配到最后的path/ident[items]或单个项.convert分支。但是从未达到最终分支,当单个项目进入宏时,生锈抱怨error: expected ident, found '1',即mactest!(1)

我作为初学者生锈用户的理由是宏有四种模式:[expr*]path[tt*]ident[tt*]expr。当我将1之类的内容传递给宏时,我不明白为什么上述任何模式都应该匹配/干扰。

有人可以解释为什么这不起作用吗?是否有解决方法来获得预期的结果?

1 个答案:

答案 0 :(得分:0)

从第一个开始并从那里开始尝试宏规则。因此,如果您想在特殊情况下阻止其他规则触发,则需要先设置特殊情况规则。

Try it out in the playground