是否可以在宏中将变量作为标识符传递?

Is it possible to pass a variable as an identifier in a macro?

我想构建一个宏来根据配置文件创建函数。我希望能够在运行时通过传递参数(即命令模式)按名称调用该函数。例如:

macro_rules! create_fn {
    ($name:ident) => {
        fn $name() {
            println!("Hello from fn {}", stringify!($name));
        }
    };
}

fn main() {
    let fn_name = "MyFunction"; //this would come from a config file
    create_fn!(fn_name);
}

简短的回答是否定的。

  • 宏只对标记进行操作,因此在程序 运行
  • 之前,宏无法找到变量的值
  • 函数名称必须在编译时已知。
  • 声明性宏(用 macro_rules! 定义的宏)不够强大,无法进行任意标记操作。

较长的答案是肯定的,但有很多限制。首先,它必须是程序宏,而不是声明宏。其次,您必须将文件名作为文字传递;它不能来自变量。

我不会详细介绍实现程序宏的细节,但它会像这样使用:

create_fn!("function_name.txt");

其中 "function_name.txt" 是一个文件,它在您的源代码中。过程宏可以读取文件并使用其中的值来定义函数。

但是不可能写出可以这样使用的宏:

let file = "function_name.txt";
create_fn!(file);

那是因为宏只会将 file 视为其输入。在程序实际运行之前,它无法确定该变量的值,但宏需要在编译时知道该名称才能写出标记。

这非常有限,很难想象它在实践中有用。也许如果配置包含用不同语言编写的函数并且您希望宏解析它们并将它们翻译成 Rust,那么它就可以工作。但我想会有更好的方法来实现这一点。