Как использовать макрос в файлах модулей?
У меня есть два модуля в отдельных файлах в одном ящике, где ядро имеет macro_rules
. Я хочу использовать макросы, определенные в одном модуле в другом модуле.
// macros.rs
#[macro_export] // or not? is ineffectual for this, afaik
macro_rules! my_macro(...)
// something.rs
use macros;
// use macros::my_macro; <-- unresolved import (for obvious reasons)
my_macro!() // <-- how?
В настоящее время я попал в ошибку компилятора "macro undefined: 'my_macro'
"... что имеет смысл; макросистема запускается перед модульной системой. Как мне обойти это?
Ответы
Ответ 1
Макросы внутри одного ящика
#[macro_use]
mod foo {
macro_rules! bar {
() => ()
}
}
bar!(); // works
Если вы хотите использовать макрос в том же ящике, модуль, в котором определен ваш макрос, нуждается в атрибуте #[macro_use]
.
Макросы можно использовать только после того, как они были определены. Это означает, что это не работает:
bar!(); // ERROR: cannot find macro 'bar!' in this scope
#[macro_use]
mod foo {
macro_rules! bar {
() => ()
}
}
Макросы через ящики
Чтобы использовать ваши macro_rules!
макрос из других ящиков, сам макрос нуждается в атрибуте #[macro_export]
. Импортирующий ящик может затем импортировать макрос с помощью use crate_name::macro_name;
,
// --- Crate 'util' ---
#[macro_export]
macro_rules! foo {
() => ()
}
// --- Crate 'user' ---
use util::foo;
foo!();
Примечание: макросы всегда живут на верхнем уровне ящика; так что даже если foo
будет внутри mod bar {}
, user
ящик все равно должен будет написать use util::foo;
и не use util::bar::foo;
,
(До Rust 2018 вы должны были импортировать макрос из других ящиков, добавив атрибут #[macro_use]
в #[macro_use]
extern crate util;
это импортировало бы все макросы из util
. Альтернативно, #[macro_use(cat, dog)]
может быть используется только для импорта макросов cat
и dog
. Этот синтаксис больше не нужен.)
Более подробная информация доступна на языке программирования Rust.
Ответ 2
Этот ответ устарел, как у Rust 1.1.0-stable.
Вам нужно добавить #![macro_escape]
вверху macros.rs
и включить его с помощью mod macros;
, как указано в Руководство по макросам.
$ cat macros.rs
#![macro_escape]
#[macro_export]
macro_rules! my_macro {
() => { println!("hi"); }
}
$ cat something.rs
#![feature(macro_rules)]
mod macros;
fn main() {
my_macro!();
}
$ rustc something.rs
$ ./something
hi
В будущем,
$ rustc -v
rustc 0.13.0-dev (2790505c1 2014-11-03 14:17:26 +0000)
Ответ 3
Добавление #![macro_use]
в начало файла, содержащего макросы, приведет к выталкиванию всех макросов в main.rs.
Например, допустим, что этот файл называется node.rs:
#![macro_use]
macro_rules! test {
() => { println!("Nuts"); }
}
macro_rules! best {
() => { println!("Run"); }
}
pub fn fun_times() {
println!("Is it really?");
}
Ваш main.rs будет выглядеть примерно так:
mod node; //We're using node.rs
mod toad; //Also using toad.rs
fn main() {
test!();
best!();
toad::a_thing();
}
Наконец, скажем, у вас есть файл с именем toad.rs, который также требует этих макросов:
use node; //Notice this is 'use' not 'mod'
pub fn a_thing() {
test!();
node::fun_times();
}
Обратите внимание, что после того, как файлы втянуты в main.rs с помощью mod
, остальные ваши файлы имеют доступ к ним с помощью ключевого слова use
.