如何将从配置文件加载的参数传递给过程宏函数?

How to pass parameters loaded from configuration file to a procedural macro function?

这是我正在尝试解决的问题。我有多个生成预计算值表的过程宏函数。目前,我的程序宏函数采用文字整数形式的参数。我希望能够从配置文件传递这些参数。我可以重写我的函数以从宏本身加载参数。但是,我想保留顶级板条箱的配置,如本例所示:

top-level-crate/
    config/
        params.yaml
    macro1-crate/
    macro2-crate/
     

因为宏函数的输入是语法标记而不是 运行 时间值,所以我无法从顶级包加载文件并传递参数。

    use macro1_crate::gen_table1;
    use macro2_crate::gen_table2;

    const TABLE1: [f32;100] = gen_table1!(500, 123, 499);
    const TABLE2: [f32;100] = gen_table2!(1, 3);

    fn main() {
       // use TABLE1 and TABLE2 to do further computation.
        
    }

我希望能够从这样的配置文件中将参数传递给 gen_table1 和 gen_table2:


    use macro1_crate::gen_table1;
    use macro2_crate::gen_table2;
   
    // Load values PARAM1, PARAM2, PARAM3, PARAM4, PARAM5

    const TABLE1: [f32;100] = gen_table1!(PARAM1, PARAM2, PARAM3);
    const TABLE2: [f32;100] = gen_table2!(PARAM4, PARAM5);

    fn main() {
       // use TABLE1 and TABLE2 to do further computation.
        
    }

明显的问题是PARAM1、PARAM2、PARAM3、PARAM4、PARAM5是运行时间值,proc宏依赖构建时间信息生成表。

我正在考虑的一个选项是创建另一个 proc 宏,专门用于将配置加载到使用 quote! 标记构建的某种数据结构中。然后将其输入宏。然而,这感觉很老套,配置文件需要加载几次。 params 数据结构也需要跨宏紧密耦合。代码可能如下所示:


    use macro1_crate::gen_table1;
    use macro2_crate::gen_table2;
   
    const TABLE1: [f32;100] = gen_table1!(myparams!());
    const TABLE2: [f32;100] = gen_table2!(myparams!());

    fn main() {
       // use TABLE1 and TABLE2 to do further computation.
        
    }

有什么改进或进一步的建议吗?

gen_table1!(myparams!()); 不起作用:宏不会像函数调用那样从内向外扩展。您的 gen_table1 宏将接收文字标记流 myparams ! () 并且无法计算此宏,因此无法访问 myparams 的“return 值”。

现在,我只看到一种真正的方法来做你想做的事:从 gen_table1gen_table2 中的文件加载参数,然后只传递包含参数的文件的文件名.例如:

const TABLE1: [f32; 100] = gen_table1!("../config/params.yaml");
const TABLE2: [f32; 100] = gen_table2!("../config/params.yaml");

当然,这可能会导致这两个宏中出现重复代码。但这应该可以用通常的工具解决:提取参数加载到一个函数中(如果两个宏都在同一个 crate 中)或另一个实用程序 crate(如果两个宏在不同的 crate 中)。


你还一直提到“运行时间价值”这个词。我 认为 你的意思是“一个常量值,而不是文字”,你指的是这样的东西:

const PARAM1: u32 = load_param!();
const TABLE1: [f32; 100] = gen_table1!(PARAM1); // <-- this does not work as expected!

因为在这里,您的宏再次接收文字标记流 PARAM1 而不是所述参数的值。

所以是的,我认为这就是“运行时间价值”的意思。当然,我现在没有更好的术语,但是“运行时间值”是 misleading/wrong,因为该值在编译时可用。如果您谈论的是实际的 运行 时间值,即编译完成后仅在 运行 时间可知的值,那么您将无法执行您想要的操作。那是因为 proc 宏 运行 在编译时出现一次,而从不在 运行 时出现。