0

我有一个macro_rules需要 afunction_name并调用function_name_x(). 现在我通过function_name作为一个传递ident,并通过创建新的函数名来做到这一点concat_idents!

这种方法的问题是我的 IDE 没有对function_name部件进行 lint,因为它需要作为ident. 我想将其更改为 a,但如果我这样做,ty我将无法使用它。concat_idents!

有解决办法吗?

macro_rules! decl_func {
    ($env:expr, $func:ident) => {{
        let f = concat_idents!($func, _to_ocaml);
        let binding = f($env, None);
        println!("{}", binding);
    }};
}
4

1 回答 1

1

从您的使用情况来看,我会说ident是正确的选择。虽然其他诸如 , path,tt之类的东西expr通常可能适合接受一个函数,因为您只是使用它来创建另一个标识符,ident因此最有意义。


通过复杂的蒙特卡罗分析,rust-analyzer 处理宏中的语法检测的方式似乎是先扩展它,评估生成的代码,然后将该信息反向引用到原始宏参数。

在下面的示例中,decl_func1调用正确地将function_name标识符链接到函数定义,而decl_func2调用没有。

fn function_name() {}

macro_rules! decl_func1 {
    ($func:ident) => {
        $func();
    };
}

macro_rules! decl_func2 {
    ($func:ident) => {};
}

fn main() {
    decl_func1!(function_name);
    decl_func2!(function_name);
}

所以在你的代码中,rust-analyzer 不会建立连接,function_name因为生成的代码只有function_name_x.


一个潜在的解决方法是在宏中引入一个语句,该语句将在语法上按原样使用标识符,但最终什么都不做。无论如何,这可能是一个好主意,这样编译器,而不仅仅是 rust-analyzer,可以验证标识符是它应该是什么。几个想法:

// would check that it is some kind of value
let _ = &$func;
// would check that it is a function with a signature that can take these types
let _ = || $func(1, 2);
于 2021-10-02T06:58:54.263 回答