Rust宏:调用依赖于表达式的函数

5

我有三个不同的函数,我想根据宏参数调用其中一个。这个参数应该被预处理,所以我认为我需要将它写成expr。然而,在宏中似乎没有找到区分不同情况的方法expr。下面是我的代码:

fn func_100(){
    println!("Func 100!");
}
fn func_200(){
    println!("Func 200!");
}
fn func_300(){
    println!("Func 300!");
}

macro_rules! generate_func_call {
    (100) => {
        func_100();
    };
    (200) => {
        func_200();
    };
    (300) => {
        func_300();
    }
}

macro_rules! generate_func_call_wrapper {
    ($func: ident, $number: expr) => {
        fn $func(){
            println!("{:?}", $number / 100);
            generate_func_call!($number);
        }
    };
}

generate_func_call_wrapper!(f1,100);
generate_func_call_wrapper!(f2,200);
generate_func_call_wrapper!(f3,300);

fn main(){
    f1();
}

这会导致以下编译时错误:

    generate_func_call!($number);
                        ^^^^^^^ no rules expected this token in macro call

我该如何修复这个程序,以便基于$number表达式调用不同的函数?

1
说实话,Rust编译器在优化方面非常出色,因此如果您在if表达式中使用常量,它会为您消除它,因此对运行时没有影响。 - hellow
1
非常相关(如果不是重复的话):https://dev59.com/jprga4cB1Zd3GeqPn4Wi - hellow
2个回答

6

您可以通过调用cargo +nightly rustc --profile=check -- -Zunstable-options --pretty=expanded或使用cargo-expand来查看宏扩展。

fn f1() {
    {
        ::std::io::_print(::std::fmt::Arguments::new_v1(
            &["", "\n"],
            &match (&(100 / 100),) {
                (arg0,) => [::std::fmt::ArgumentV1::new(arg0, ::std::fmt::Debug::fmt)],
            },
        ));
    };
    ();
}

您可以看到最后一个 (); 应该是 func_100()
这是因为在 generate_func_call 中没有类型为 ($number: expr) 的 token 规则,即没有匹配扩展的规则。这是因为在函数中,$number 没有像您预期的那样被替换为 100。宏根据其收到的片段类型创建更多的 Rust 代码,而不是尝试评估任何内容。
将代码更改为:
macro_rules! generate_func_call {
    ($number: expr) => {
        match $number {
            100 => func_100(),
            200 => func_200(),
            300 => func_300(),
            _ => (),
        }
    };
}

最后,(); 改变为:
match 300 {
    100 => func_100(),
    200 => func_200(),
    300 => func_300(),
    _ => (),
};

您无需担心额外的跳转语句或类似问题,因为它会被优化为编译时常量300,并且会转换为func_300()


0

看起来它根本不受支持。

类似问题#1 类似问题#2

一个可能的解决方法是在第一个宏中匹配文字,就像在这个playground中一样。虽然这只会引入更多的代码重复。

将来可能可以使用const fn功能来实现这一点,就像在这个playground中一样。但你必须等待功能被实现

现在我建议仅在运行时使用正则表达式match来匹配值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接