Макросы

Процедурные макросы

Последнее обновление: 01.08.2024

Процедурный макрос позволяет вставлять произвольный код Rust в исходный код программы. При этом входные данные для макроса представляют проанализированныме токенам, соответствующим некоторому фрагменту исходного исходного кода.

Процедурные макросы должны размещаться в отдельном крейте, который должен иметь тип proc-macro. Есть 3 типа процедурных макросов:

  • Макросы-функции. Вызываются подобно функциям с передачей им аргументов

  • Макросы-атрибуты. Прикрепляются к некоторому фрагменту синтаксиса в программе

  • Derive-макросы. Прикрепляются к определению структуры данных

Функциональные макросы

РАссмотрим функциональные макросы. Для этого создадим новый проект cargo, например, он будет называться macroapp:

cargo new macroapp

В созданном проекте изменим файл Cargo.toml:

[package]
name = "macroapp"
version = "0.1.0"
edition = "2021"

[lib]
proc-macro = true

[dependencies]

Здесь добавлена секция [lib], в которой задан тип крейта proc-macro = true

Далее в папку src добавим новый файл lib.rs, где определим следующий код:

use proc_macro::TokenStream;

#[proc_macro]
pub fn my_func_macro(args: TokenStream) -> TokenStream {
    println!("Поток токенов:");
    for tt in args {
        println!(" {tt:?}");
    }
    // возвращаем пустой поток токенов
    TokenStream::new()
}

Функциональный макрос предваряется атрибутом #[proc_macro]. В качестве параметра функция макроса получает поток токенов - TokenStream. В данном случае просто выводим токены на консоль.

В файле main.rs в папке src протестируем макрос:

use macroapp::my_func_macro;

fn main() {
    my_func_macro!(let x = (n)=> n*n;);
}

Здесь в макрос передается произвольный код - let x = (n)=> n*n; (не столь важно, какой это код - языка Rust или нет, валидный или нет). На уровне макроса этот код превратится в поток токенов. B ghb pfgecrt проекта с помощью cargo run мы получим следующий вывод:

Поток токенов:
 Ident { ident: "let", span: #0 bytes(63..66) }
 Ident { ident: "x", span: #0 bytes(67..68) }
 Punct { ch: '=', spacing: Alone, span: #0 bytes(69..70) }
 Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "n", span: #0 bytes(72..73) }], span: #0 bytes(71..74) }
 Punct { ch: '=', spacing: Joint, span: #0 bytes(74..75) }
 Punct { ch: '>', spacing: Alone, span: #0 bytes(75..76) }
 Ident { ident: "n", span: #0 bytes(76..77) }
 Punct { ch: '*', spacing: Alone, span: #0 bytes(77..78) }
 Ident { ident: "n", span: #0 bytes(78..79) }
 Punct { ch: ';', spacing: Alone, span: #0 bytes(79..80) }
Помощь сайту
Юмани:
410011174743222
Номер карты:
4048415020898850