Как использовать макросы в нескольких файлах модулей Rust?
Проблема экспорта макросов в Rust
В Rust макросы (определённые через macro_rules!) по умолчанию видны только в том модуле, где они объявлены, и в его дочерних модулях (после объявления макроса). Это отличается от функций, которые можно сделать публичными через pub. Для макросов работает другой механизм — атрибут #[macro_export].
Решение: используйте #[macro_export]
Чтобы макрос был доступен во всех модулях вашего проекта (и даже для внешних крейтов), нужно пометить его атрибутом #[macro_export]. Вот как исправить ваш код:
1. В main.rs (или отдельном файле для макросов):
// main.rs
#[macro_export]
macro_rules! my_println {
($($arg:tt)*) => {
println!("[LOG] {}", format!($($arg)*));
};
}
mod utils;
2. В utils/helper.rs макрос теперь будет доступен:
// utils/helper.rs
pub fn do_something() {
my_println!("Hello from helper!");
}
Как это работает?
#[macro_export]делает макрос доступным в корне вашего крейта (crate root). После этого его можно использовать в любом модуле, просто обращаясь по имени.- Макросы с
#[macro_export]автоматически становятся публичными и доступны для других крейтов, если ваш крейт используется как зависимость. - Важно: макрос должен быть определён до того, как он используется в модулях. Обычно их помещают в начало файла
lib.rsилиmain.rs.
Альтернативный способ: вынести макросы в отдельный модуль
Если макросов много, удобнее вынести их в отдельный файл, например macros.rs, и подключить его через #[macro_use]:
// src/macros.rs
#[macro_export]
macro_rules! my_println {
($($arg:tt)*) => {
println!("[LOG] {}", format!($($arg)*));
};
}
// src/main.rs
#[macro_use]
mod macros;
// Теперь макросы из macros.rs доступны во всём крейте
mod utils;
Атрибут #[macro_use] перед mod macros; импортирует все экспортированные макросы из этого модуля в текущую область видимости.
Важные нюансы
- Порядок объявления: макросы должны быть объявлены до их использования в коде модулей. Если модуль определён раньше макроса, компилятор выдаст ошибку.
- Макросы и
pub: атрибут#[macro_export]— это единственный способ сделать макрос публичным. Просто написатьpub macro_rules!нельзя. - Для внешних крейтов: если вы пишете библиотеку, экспортированные макросы будут доступны пользователям вашего крейта через
use my_crate::my_macro;(начиная с Rust 2018).
Теперь ваш макрос my_println! будет работать в utils/helper.rs и любом другом модуле проекта.
Использование #[macro_use] на уровне модуля
Если вы не хотите помечать каждый макрос атрибутом #[macro_export], можно использовать атрибут #[macro_use] на объявлении модуля. Это импортирует все макросы из указанного модуля (даже неэкспортированные) в текущую область видимости.
Пример:
// src/macros.rs — без #[macro_export]
macro_rules! my_println {
($($arg:tt)*) => {
println!("[LOG] {}", format!($($arg)*));
};
}
// src/main.rs
#[macro_use]
mod macros; // Импортируем все макросы из macros.rs
mod utils;
// Теперь my_println! доступен и в main.rs, и в utils/helper.rs
Недостаток: такой подход работает только в пределах одного крейта. Если вы хотите, чтобы макрос был доступен из других крейтов (например, при публикации библиотеки), обязательно используйте #[macro_export].
Дополнительный совет: в Rust 2018+ можно использовать macro_use также в выражении extern crate, чтобы импортировать макросы из внешних зависимостей, но для внутренних модулей описанный выше способ — самый простой.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги