Почему я не могу сопоставить тело структуры, используя `block` matcher в макросе Rust? - PullRequest
0 голосов
/ 04 сентября 2018

Я пытаюсь сопоставить struct в макросе Rust. Мне нужно вытащить 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 голосов
/ 07 октября 2018

Соответствие $:block предназначено для блочных выражений, то есть набора фигурных скобок, содержащих ноль или более операторов и элементов Rust и необязательное конечное возвращаемое значение. Например, следующие блоки:

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

Примеры фигурных скобок в Rust, которые являются блоками:

  • функциональные тела,
  • if и else пункты,
  • тела петель for, while и loop петель.

Фигурные скобки вокруг полей структуры не являются блоком, поскольку они не должны содержать ноль или более операторов Rust и элементов, за которыми следует необязательное конечное возвращаемое значение. Вместо этого они должны содержать имена и типы полей структуры.

В макросе вы можете сопоставить произвольный набор фигурных скобок, используя шаблон { $($tt:tt)* }, что означает «фигурные скобки, содержащие любое количество произвольных токенов».

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

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