宏可以匹配常量参数而不是文字吗?

时间:2016-09-06 12:42:25

标签: macros rust

鉴于macro matching example,这显示了宏如何匹配参数。

我在这里做了很小的改动以使用数字:

macro_rules! foo {
    (0 => $e:expr) => (println!("mode X: {}", $e));
    (1 => $e:expr) => (println!("mode Y: {}", $e));
}

fn main() {
    foo!(1 => 3);
}

作品,打印:mode Y: 3

但是我想使用常量作为参数,可以使它起作用:

const CONST: usize = 1;

macro_rules! foo {
    (0 => $e:expr) => (println!("mode X: {}", $e));
    (1 => $e:expr) => (println!("mode Y: {}", $e));
}

fn main() {
    foo!(CONST => 3);
}

这可能在Rust吗?

注意,使用常规match语句对我来说是不可用的,因为在我的代码中,每个分支都会解析为不同的类型,从而产生错误。 所以我特别想知道是否可以将常量传递给宏。

3 个答案:

答案 0 :(得分:4)

我很确定答案是“不”;在宏扩展时,你所拥有的只是标记树 - 扩展在评估之前发生,甚至是类型推断/检查。

答案 1 :(得分:4)

宏在Abstract 语法树上运行,因此他们在语法层面上推理:他们推理令牌和他们的拼写

例如:

fn main() {
    let v = 3;
}

在这种情况下,AST看起来像:

fn main
    \_ let-binding v
        \_ literal 3

如果你问一个宏v3,它会让你看起来很有趣,并想知道你为什么要尝试比较一个变量名和一个文字。

答案 2 :(得分:0)

const CONST: usize = 0;

macro_rules! foo {
    ($i:ident => $e:expr) => {
        if $i == 0 {
            println!("mode X: {}", $e);
        } else if $i == 1 {
            println!("mode Y: {}", $e);
        }
    };
}

fn main() {
    foo!(CONST => 3);
}

如果你想在宏中使用标识符,它需要是 ident 标签,你可以使用 if, else if 块而不是 match