Ошибка макроса при попытке реализовать черту внутри макроса

fn a() {} кажется, удовлетворяет правилу синтаксического анализа, который ожидал fnи другие вещи. items должен быть в состоянии быть определениями функций, верно? Значит, они должны работать, верно?

macro_rules! multi_impl {
    (for $base:ty :
        $($t:ty {
            $($i:item);*
        }),+) =>
    {
        $(
            impl $t for $base
            {
                $( $i )*
            }
        )+
    }
}

trait A {
    fn a();
}

trait B {
    fn b();
}

struct S;

multi_impl! {
    for S:
    A {
        fn a() {}
    }, B {
        fn b() {}
    }
}

fn main() {
    S::a();
    S::b();
}

детская площадка

Ошибка в вопросе:

error: expected one of `const`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `fn a() { }`
  --> <anon>:11:20
   |
11 |                 $( $i )*
   |                    ^^

Делая это $( fn $i)* только изменяет ошибку, чтобы пожаловаться на ожидание идентификатора после fn, что имеет смысл, но первоначальной ошибки нет (по крайней мере, для меня).

Есть ли разница в синтаксическом анализаторе относительно кода, который находится в исходном коде против кода, который помещается в исходный код макросом?

1 ответ

Решение

Проблема не в том, что fn это не предмет, это то, что тело impl не содержит предметов Содержит "предметы". На что он жалуется, так это на то, что вы пытаетесь положить квадратный блок в круглое отверстие, а не на то, что блок имеет неправильный цвет.

Да, это две разные вещи. Нет, вы не можете захватить "элементы impl" в макросе. Нет, вы не можете превратить предмет в неявный предмет. Потому что макросы захватывают узлы AST, а не токены. Ну, методы могут иметь self аргумент и обычная функция не делают. Я не знаю, по-видимому, в то время это казалось хорошей идеей.

Если оставить в стороне гипотетический вопрос, решение в этом случае состоит в том, чтобы не пытаться сопоставить что-либо конкретное и просто сопоставить что-либо.

macro_rules! multi_impl
{
    (for $base:ty :
        $($t:ty {
            $($body:tt)*
        }),+) =>
    {
        $(
            impl $t for $base
            {
                $($body)*
            }
        )+
    }
}
Другие вопросы по тегам