在嵌套的rust宏中动态创建参数



我已经对Rust的宏系统进行了一段时间的修改,最近对将两个宏嵌套在一起感兴趣,比如:

macro_rules! foo {
() => {
macro_rules! bar {
() => {}
}
}
}

关于这个例子,我想在bar!中动态地创建参数名称,这些名称被传递到foo!中,以获得这样的结果:

foo!(bar, baz); 
// The above call creates a macro, bar!, with the following definition:
macro_rules! bar {
( $bar:literal, $baz:literal ) => {
println!("{}", stringify!( $bar, $baz ));
}
}

为了更好地了解我正在尝试做什么,以下是我对如何工作的最初思考过程(这应该完全解析为上面显示的定义(:

macro_rules! foo {
( $( $attr:ident ), * ) => {
macro_rules! bar {
// the designator $$attr:literal consists of two parts - $attr,
// which should be replaced with the arguments passed into foo!,
// and $__:literal, which creates a literal designator for each of
// the arguments from foo! for bar!
( $( $$attr:literal ), * ) => {
// $( $$attr ), * follows the same logic as above
println!("{}", stringify!( $( $$attr ), * ));
}
}
}
}

这看起来确实很奇怪,果不其然,它没有起作用,给出了一个提到元变量表达式和这个问题的错误,这两者看起来都不相关(在操场上可以看到完整的错误(。

有人知道是否可以用这样的变量动态创建一个宏吗?如果可以,怎么做?

是的,但是。。。

不能插入$符号,因为它是为元变量保留的。

你有两种选择来解决这个问题。

在稳定时,需要将$传递给宏。然后它可以使用元变量引用它。

macro_rules! foo {
( $dollar:tt $( $attr:ident ), * ) => {
macro_rules! bar {
( $( $dollar $attr:literal ), * ) => {
println!("{}", stringify!( $( $dollar $attr ), * ));
}
}
}
}
foo!($ bar, baz);

游乐场。

在夜间,您可以避开美元符号:这是编译器提到的macro_metavar_expr功能的一部分。使用$$:

#![feature(macro_metavar_expr)]
macro_rules! foo {
( $( $attr:ident ), * ) => {
macro_rules! bar {
( $( $$ $attr:literal ), * ) => {
println!("{}", stringify!( $( $$ $attr ), * ));
}
}
}
}
foo!(bar, baz);

游乐场。

最新更新