В следующем подразделе мы посмотрим как в Rust объявить макрос. Есть три основные идеи:
• Шаблоны и указатели
• Перегрузка
• Повторение
Аргументы макроса имеют префикс знака доллара $ и тип аннотируется с помощью
macro_rules! create_function {
// Этот макрос принимает аргумент идентификатора `ident` и
// создаёт функцию с именем `$func_name`.
// Идентификатор `ident` используют для обозначения имени переменной/функции.
($func_name:ident) => (
fn $func_name() {
// Макрос `stringify!` преобразует `ident` в строку.
println!("Вызвана функция {:?}()",
stringify!($func_name))
}
)
}
// Создадим функции с именами `foo` и `bar` используя макрос, указанный выше.
create_function!(foo);
create_function!(bar);
macro_rules! print_result {
// Этот макрос принимает выражение типа `expr` и напечатает
// его как строку вместе с результатом.
// Указатель `expr` используют для обозначения выражений.
($expression:expr) => (
// `stringify!` преобразует выражение в строку *без изменений*.
println!("{:?} = {:?}",
stringify!($expression),
$expression);
)
}
fn main() {
foo();
bar();
print_result!(1u32 + 1);
// Напомним, что блоки тоже являются выражениями!
print_result!({
let x = 1u32;
x * x + 2 * x - 1
});
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Это список всех указателей:
• block
• expr используют для обозначения выражений
• ident используют для обозначения имени переменной/функции
• item
• literal используется для литеральных констант
• pat (
• path
• stmt (
• tt (
• ty (
• vis (
Полный список указателей, вы можете увидеть в Rust Reference.
Макросы могут быть перегружены, принимая различные комбинации аргументов. В этом плане, macro_rules! может работать аналогично блоку сопоставления (match):
// `test!` будет сравнивать `$left` и `$right`
// по разному, в зависимости от того, как вы объявите их:
macro_rules! test {
// Не нужно разделять аргументы запятой.
// Можно использовать любой шаблон!
($left:expr; and $right:expr) => (
println!("{:?} и {:?} это {:?}",
stringify!($left),
stringify!($right),
$left && $right)
);
// ^ каждый блок должен заканчиваться точкой с запятой.
($left:expr; or $right:expr) => (
println!("{:?} или {:?} это {:?}",
stringify!($left),
stringify!($right),
$left || $right)
);
}
fn main() {
test!(1i32 + 1 == 2i32; and 2i32 * 2 == 4i32);
test!(true; or false);