为什么我无法在 Rust 宏中使用“block”匹配器来匹配结构体?

Phi*_*ord 2 macros rust

我正在尝试匹配structRust 宏中的 a 。我需要把它 struct稍微拆开才能得到它的名字。我认为块匹配器可以解决这个问题。考虑一下,例如:

macro_rules! multi {
    (struct $name:ident $block:block) => {
        enum George {$name}
    }
}

multi!{
    struct Fred {
        a:String
    }
}
Run Code Online (Sandbox Code Playgroud)

扩展到

enum George { Fred, }
Run Code Online (Sandbox Code Playgroud)

这是正确的。

但是,如果我将其转回 a struct,则会失败。

macro_rules! multi {
    (struct $name:ident $block:block) => {
        struct $name $block
    }
}
Run Code Online (Sandbox Code Playgroud)

这给出了这个错误。

macro_rules! multi {
    (struct $name:ident $block:block) => {
        enum George {$name}
    }
}

multi!{
    struct Fred {
        a:String
    }
}
Run Code Online (Sandbox Code Playgroud)

看起来像是{a: String}被视为单个令牌,而不是被重新解析;但这就是里面应该发生的事情。

dto*_*nay 5

匹配$:block器用于块表达式,即一组包含零个或多个 Rust 语句和项以及可选尾随返回值的花括号。例如以下是块:

{
    let x = 1;
}
Run Code Online (Sandbox Code Playgroud)
{
    #[derive(Default)]
    struct S;
    S::default()
}
Run Code Online (Sandbox Code Playgroud)

Rust 中作为块的花括号的示例有:

  • 功能机构,
  • ifelse条款,
  • forwhile、 和循环的循环体loop

结构体字段周围的大括号不是一个块,因为它们不应该包含零个或多个 Rust 语句和项目,后跟可选的尾部返回值。相反,它们应该包含结构字段的名称和类型。

在宏中,您可以使用模式匹配任意一组花括号{ $($tt:tt)* },这意味着“包含任意数量的任意标记的花括号”。

macro_rules! multi {
    (struct $name:ident { $($tt:tt)* }) => {
        struct $name { $($tt)* }
    };
}

multi! {
    struct Fred {
        a: String,
    }
}
Run Code Online (Sandbox Code Playgroud)