如何以递归方式获取宏的最后一个参数?

时间:2017-02-11 02:20:56

标签: macros rust

使用一个简单的递归宏,如下面的例子所示,它常见于第一个参数,然后是其余的。

macro_rules! count_tts {
    () => {0usize};
    ($_head:tt $($tail:tt)*) => {1usize + count_tts!($($tail)*)};
}

有没有办法以递归方式取最后一个参数?

这使得:

成为可能

类似于($($head:tt)* $tail:tt) ......但这不起作用。

1 个答案:

答案 0 :(得分:2)

宏解析器中没有“回溯”,因此不能直接使用$($head:tt)* $tail:tt执行此操作。但你可以自己扭转它来做到这一点。

macro_rules! concat_reverse {
    ([] $($reversed:tt)*) => { 
        concat!($(stringify!($reversed)),*)  // base case
    };
    ([$first:tt $($rest:tt)*] $($reversed:tt)*) => { 
        concat_reverse!([$($rest)*] $first $($reversed)*)  // recursion
    };
}

fn main() {
    println!("{}", concat_reverse!([e d c b a]))
    // output: abcde
}

宏跟踪如下所示:

   concat_reverse!([e d c b a])
== concat_reverse!([d c b a] e)
== concat_reverse!([c b a] d e)
== concat_reverse!([b a] c d e)
== concat_reverse!([a] b c d e)
== concat_reverse!([] a b c d e)
== concat!(stringify!(a), stringify!(b), stringify!(c), stringify!(d), stringify!(e))

你可以在递归阶段做一些“map”和“reduce”操作(例如用于计数)。

请注意,此方法会占用您的递归深度,您可能需要提升#![recursion_limit="..."]