Что означает символ @ в декларативном макросе?

Я видел @ символ используется в макросах, но я не могу найти упоминания о нем в Rust Book или в любой официальной документации или сообщениях в блоге. Например, в этом ответе переполнения стека он используется так:

macro_rules! instructions {
    (enum $ename:ident {
        $($vname:ident ( $($vty: ty),* )),*
    }) => {
        enum $ename {
            $($vname ( $($vty),* )),*
        }

        impl $ename {
            fn len(&self) -> usize {
                match self {
                    $($ename::$vname(..) => instructions!(@count ($($vty),*))),*
                }
            }
        }
    };

    (@count ()) => (0);
    (@count ($a:ty)) => (1);
    (@count ($a:ty, $b:ty)) => (2);
    (@count ($a:ty, $b:ty, $c:ty)) => (3);
}

instructions! {
    enum Instruction {
        None(),
        One(u8),
        Two(u8, u8),
        Three(u8, u8, u8)
    }
}

fn main() {
    println!("{}", Instruction::None().len());
    println!("{}", Instruction::One(1).len());
    println!("{}", Instruction::Two(1, 2).len());
    println!("{}", Instruction::Three(1, 2, 3).len());
}

В результате использования выясняется, что он используется для объявления другого макроса, который является локальным по отношению к основному.

Что означает этот символ и почему вы используете его, а не просто создаете другой макрос верхнего уровня?

1 ответ

Решение

В части макроса, совпадающей с шаблоном, символы могут означать то, что автор хочет, чтобы они имели в виду. Ведущий символ @ часто используется для обозначения "детали реализации" макроса - части макроса, которую внешний пользователь не должен использовать.

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

Помимо макросов, @ Символ используется для сопоставления с шаблоном при назначении имени всему шаблону:

match age {
    x @ 0 => println!("0: {}", x),
    y @ 1 => println!("1: {}", y),
    z => println!("{}", z),
}

С некоторой растяжкой эту же логику можно применить к использованию в макросе - мы сопоставляем шаблон с кортежем, но также прикрепляем имя к этому конкретному шаблону. Я думаю, что я даже видел, как люди используют что-то еще более параллельное: (count @ ..., Тем не менее, "Маленькая книга макросов ржавчины" указывает:

Причина использования @ является то, что с Rust 1.2, @ токен не используется в позиции префикса; как таковой, он не может конфликтовать ни с чем. Другие символы или уникальные префиксы могут использоваться по желанию, но использование @ начал широко распространяться, поэтому его использование может помочь читателям понять ваш код.


а не просто создание другого макроса верхнего уровня

Создание другого макроса, вероятно, является лучшей практикой, но только в современном Rust. До недавних изменений в Rust, которые позволили вам импортировать макросы напрямую, иметь несколько макросов было непросто для конечных пользователей, которые пытались выборочно импортировать макросы.

Смотрите также:

Другие вопросы по тегам