【问题标题】:Ordering macro argument execution排序宏参数执行
【发布时间】:2016-10-02 12:15:32
【问题描述】:

我正在使用一个用于字符串实习的库 (string-cache),它使用宏来高效地创建元素 (atom!)。但是为了简化,这里有一个类似的宏来演示这个问题

macro_rules! string_intern {
   ("d") => ("Found D");
}

说我需要从另一个宏调用这个宏,并给它一个字符串版本的标识符。

macro_rules! print_ident {
    ($id:ident) => (
        string_intern!(stringify!($id));
    );
}

但是调用这个宏

fn main() {
    print_ident!(d);
}

因错误而失败:

error: no rules expected the token `stringify`
 --> <anon>:7:24
  |
7 |         string_intern!(stringify!($id));
  |                        ^^^^^^^^^

Playground link

我知道stringify! 正确地将标识符d 转换为字符串"d",因为将它提供给println! 可以按预期工作。有没有办法将我想要转换为字符串的标识符传递给string_intern

【问题讨论】:

    标签: macros rust


    【解决方案1】:

    println! 允许您这样做,因为它在幕后使用format_args!,这是编译器提供的“内在”,它在使用它之前 强制评估它的第一个参数。您不能从用户定义的宏中执行此操作;你必须编写一个编译器插件(它需要一个夜间编译器并且不能保证稳定性)。

    所以,是的;你不能。对不起。您唯一能做的就是重新定义宏,使您不需要 一个实际的字符串文字,或者更改调用它的方式。

    【讨论】:

      【解决方案2】:

      您对string_intern! 的定义是期望一个文字"d" 而没有别的,但是您正在传递这些标记:stringify!,...这就是它失败的原因。你想要的string_intern!的定义大概是:

      macro_rules! string_intern {
          ($e:expr) => {
              match $e {
                  "d" => "Found D",
                  _ => "Not found",
              }
          }
      }
      

      它可以接受任何计算结果为字符串类型的表达式。

      【讨论】:

      • 这只是一个简写。基本上,我不能要求你下载string-cache 来解决这个例子,所以这是这个问题的MVP。
      • @DanielFath 啊!我想我没有正确理解你的意图......所以你绝对想要编译时匹配......
      最近更新 更多