【问题标题】:Can macros match against constant arguments instead of literals?宏可以匹配常量参数而不是文字吗?
【发布时间】:2016-09-06 12:42:25
【问题描述】:

鉴于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 语句对我来说不可用,因为在我的代码中,每个分支都解析为不同的类型,从而产生错误。 所以我特别想知道是否可以将常量传递给宏。

【问题讨论】:

  • 您说“每个分支都解析为不同的类型”。能举个例子吗?

标签: macros rust


【解决方案1】:

没有。

宏在抽象语法树上运行,因此它们在句法级别进行推理:它们对标记及其拼写进行推理。 p>

例如:

fn main() {
    let v = 3;
}

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

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

如果您询问宏 v 是否为 3,它会觉得您很有趣,并想知道您为什么要尝试比较变量名和文字。

【讨论】:

  • 我认为这不是 完全 AST - 宏被赋予未完全解析的标记(因为,当然,宏部分定义了如何解析它们)。我说的是未完全解析而不是未解析,因为您确实有 $e:expr
  • @ChrisEmerson:是的,比这要宽松一点。
【解决方案2】:

我很确定答案是否定的;在宏扩展时,您所拥有的只是令牌树 - 扩展发生在评估之前,甚至是类型推断/检查。

【讨论】:

    【解决方案3】:
    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标签,你可以使用ifelse if块代替match

    【讨论】:

    • 请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助、质量更好,并且更有可能吸引投票。
    • 感谢警告。
    猜你喜欢
    • 1970-01-01
    • 2013-05-16
    • 1970-01-01
    • 2011-11-02
    • 2016-07-14
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 2023-03-25
    相关资源
    最近更新 更多