Макросы позволяют вам писать код, который пишет другой код. Узнайте о странном и мощном мире метапрограммирования.

Генерация кода — это функция, которую вы найдете в большинстве современных языков программирования. Это может помочь вам сократить шаблонный код и дублирование кода, определить доменные языки (DSL) и внедрить новый синтаксис.

Rust предоставляет мощную систему макросов, которая позволяет вам генерировать код во время компиляции для более сложного программирования.

Введение в макросы Rust

Макросы — это тип метапрограммирования, который вы можете использовать для написания кода, который пишет код. В Rust макрос — это фрагмент кода, который генерирует другой код во время компиляции.

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

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

instagram viewer
Функции ржавчины потому что они работают с кодом, а не с данными во время выполнения.

Определение макросов в Rust

Вы будете определять макросы с макрос_правила! макрос. макрос_правила! макрос принимает шаблон и шаблон в качестве входных данных. Rust сопоставляет шаблон с входным кодом и использует шаблон для генерации выходного кода.

Вот как вы можете определить макросы в Rust:

макрос_правила! скажи привет {
() => {
распечатать!("Привет, мир!");
};
}

фносновной() {
скажи привет!();
}

Кодекс определяет скажи привет макрос, который генерирует код для печати «Hello, world!». Код соответствует () синтаксис против пустого ввода и распечатать! макрос генерирует выходной код.

Вот результат запуска макроса в основной функция:

Макросы могут принимать входные параметры для сгенерированного кода. Вот макрос, который принимает один аргумент и генерирует код для печати сообщения:

макрос_правила! сказать_сообщение {
($ сообщение: выражение) => {
распечатать!("{}", $сообщение);
};
}

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

Типы макросов Rust

Rust предоставляет три типа макросов. Каждый из типов макросов служит определенным целям, и у них есть свой синтаксис и ограничения.

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

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

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

Пользовательские макросы, похожие на атрибуты, удобны для добавления пользовательских аннотаций в код Rust. Веб-фреймворк Rocket использует настраиваемый макрос, похожий на атрибут, для краткого и удобочитаемого определения маршрутов.

Вы можете использовать пользовательские макросы, подобные функциям, для определения новых выражений или операторов Rust. Крейт Lazy_static использует пользовательский макрос, похожий на функцию, для определения ленивая инициализация статические переменные.

Вот как вы можете определить процедурный макрос, который определяет пользовательский макрос вывода:

использовать proc_macro:: TokenStream;
использовать цитата:: цитата;
использовать syn::{DeriveInput, parse_macro_input};

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

#[proc_macro_derive (MyTrait)]
пабфнmy_derive_macro(вход: TokenStream) -> TokenStream {
позволять ast = parse_macro_input!(ввод как Получить ввод);
позволять имя = &ast.ident;

позволять ген = цитата! {
импл MyTrait для #имя {
// реализация здесь
}
};

род.в()
}

Программа определяет процедурный макрос, который генерирует реализацию трейта для структуры или перечисления. Программа вызывает макрос с именем MyTrait в производном атрибуте структуры или перечисления. Макрос занимает TokenStream объект в качестве входных данных, содержащий код, преобразованный в абстрактное синтаксическое дерево (AST) с parse_macro_input! макрос.

имя переменная — производная структура или идентификатор перечисления, цитировать! Макрос генерирует новый AST, представляющий реализацию MyTrait для типа, который в итоге возвращается как TokenStream с в метод.

Чтобы использовать макрос, вам нужно импортировать макрос из модуля, в котором вы его объявили:

// если вы объявили макрос в модуле my_macro_module

использовать my_macro_module:: my_derive_macro;

При объявлении структуры или перечисления, использующего макрос, вы добавите #[получить (MyTrait)] в начало объявления.

#[получить (MyTrait)]
структураМояСтруктура {
// поля здесь
}

Объявление структуры с атрибутом расширяется до реализации MyTrait черта для структуры:

импл MyTrait для МояСтруктура {
// реализация здесь
}

Реализация позволяет использовать методы в MyTrait черта на МояСтруктура экземпляры.

Макросы атрибутов

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

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

Вот макрос атрибута, который добавляет пользовательский атрибут в структуру Rust:

// импорт модулей для определения макроса
использовать proc_macro:: TokenStream;
использовать цитата:: цитата;
использовать syn::{parse_macro_input, DeriveInput, AttributeArgs};

#[proc_macro_attribute]
пабфнmy_attribute_macro(атрибут: TokenStream, элемент: TokenStream) -> TokenStream {
позволять args = parse_macro_input!(attr как Аргументы атрибутов);
позволять ввод = parse_macro_input!(элемент как Получить ввод);
позволять имя = &input.ident;

позволять ген = цитата! {
#вход
импл #имя {
// пользовательское поведение здесь
}
};

род.в()
}

Макрос принимает список аргументов и определение структуры и создает измененную структуру с определенным пользовательским поведением.

Макрос принимает на вход два аргумента: атрибут, применяемый к макросу (анализируемый с помощью parse_macro_input! макрос) и элемент (проанализированный с помощью parse_macro_input! макрос). В макросе используется цитировать! макрос для генерации кода, включая исходный элемент ввода и дополнительный импл блок, определяющий пользовательское поведение.

Наконец, функция возвращает сгенерированный код в виде TokenStream с в() метод.

Правила макросов

Правила макросов — это самый простой и гибкий тип макросов. Правила макросов позволяют вам определять собственный синтаксис, который расширяется до кода Rust во время компиляции. Правила макросов определяют пользовательские макросы, которые соответствуют любому выражению или оператору rust.

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

Вот как вы можете определить и использовать правила макросов в своих программах на Rust:

макрос_правила! сделать_вектор {
( $( $x: выражение ),* ) => {
{
позволятьмут v = Век::новый();
$(
v.push($x);
)*
в
}
};
}

фносновной() {
позволять v = сделать_вектор![1, 2, 3];
распечатать!("{:?}", в); // печатает "[1, 2, 3]"
}

Программа определяет сделать_вектор! макрос, который создает новый вектор из списка разделенных запятыми выражений в основной функция.

Внутри макроса определение шаблона соответствует аргументам, переданным в макрос. $($x: выражение),* синтаксис соответствует любым выражениям, разделенным запятыми, определенным как .

$( ) синтаксис в коде расширения перебирает каждое выражение в списке аргументов, переданных макросу после закрывающая скобка, указывающая, что итерации должны продолжаться до тех пор, пока макрос не обработает все выражения.

Эффективно организуйте свои проекты на Rust

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

Кроме того, вы можете организовывать программы Rust в крейты и модули для лучшей организации кода, повторного использования и взаимодействия с другими крейтами и модулями.