为什么我不能在Rust宏中使用“块”匹配器来匹配结构体?

时间:2018-09-04 07:18:49

标签: macros rust

我正在尝试在Rust宏中匹配struct。我需要拉 struct彼此分开以获得其名称。我发现那个街区 匹配者可以解决问题。例如,考虑一下:

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

multi!{
    struct Fred {
        a:String
    }
}

扩展为

enum George { Fred, }

大约是正确的。

但是,如果我将其改回struct,它将失败。

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

出现此错误。

 error: expected `where`, `{`, `(`, or `;` after struct name, found `{ a: String }`
   --> src/main.rs:64:22
    |
 64 |           struct $name $block
    |                        ^^^^^^ expected `where`, `{`, `(`, or `;` after struct name

似乎{a: String}被视为单个令牌,而不是 而不是重新解析;但这应该是在那里。

1 个答案:

答案 0 :(得分:2)

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

{
    let x = 1;
}
{
    #[derive(Default)]
    struct S;
    S::default()
}

Rust中大括号的示例是块

  • 功能主体
  • ifelse子句,
  • forwhileloop循环的循环体。

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

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

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

multi! {
    struct Fred {
        a: String,
    }
}