问题
I have two modules in separate files within the same crate, where the crate has macro_rules
enabled. I want to use the macros defined in one module in another module.
// 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?
I currently hit the compiler error "macro undefined: 'my_macro'
"... which makes sense; the macro system runs before the module system. How do I work around that?
回答1:
Macros within the same crate
#[macro_use]
mod foo {
macro_rules! bar {
() => ()
}
}
bar!(); // works
If you want to use the macro in the same crate, the module your macro is defined in needs the attribute #[macro_use]
.
Macros can only be used after they have been defined. This means that this does not work:
bar!(); // ERROR: cannot find macro `bar!` in this scope
#[macro_use]
mod foo {
macro_rules! bar {
() => ()
}
}
Macros across crates
To use your macro_rules!
macro from other crates, the macro itself needs the attribute #[macro_export]
. The importing crate can then import the macro via use crate_name::macro_name;
.
Crate util
#[macro_export]
macro_rules! foo {
() => ()
}
Crate user
use util::foo;
foo!();
Note that macros always live at the top-level of a crate; so even if foo
would be inside a mod bar {}
, the user
crate would still have to write use util::foo;
and not use util::bar::foo;
.
Before Rust 2018, you had to import macro from other crates by adding the attribute #[macro_use]
to the extern crate util;
statement. That would import all macros from util
. Alternatively, #[macro_use(cat, dog)]
could be used to only import the macros cat
and dog
. This syntax should not be necessary anymore.
More information is available in The Rust Programming Language chapter on macros.
回答2:
This answer is outdated as of Rust 1.1.0-stable.
You need to add #![macro_escape]
at the top of macros.rs
and include it using mod macros;
as mentioned in the Macros Guide.
$ 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
For future reference,
$ rustc -v
rustc 0.13.0-dev (2790505c1 2014-11-03 14:17:26 +0000)
回答3:
Adding #![macro_use]
to the top of your file containing macros will cause all macros to be pulled into main.rs.
For example, let's assume this file is called node.rs:
#![macro_use]
macro_rules! test {
() => { println!("Nuts"); }
}
macro_rules! best {
() => { println!("Run"); }
}
pub fn fun_times() {
println!("Is it really?");
}
Your main.rs would look sometime like the following:
mod node; //We're using node.rs
mod toad; //Also using toad.rs
fn main() {
test!();
best!();
toad::a_thing();
}
Finally let's say you have a file called toad.rs that also requires these macros:
use node; //Notice this is 'use' not 'mod'
pub fn a_thing() {
test!();
node::fun_times();
}
Notice that once files are pulled into main.rs with mod
, the rest of your files have access to them through the use
keyword.
回答4:
I have came across the same problem in Rust 1.44.1, and this solution works for later versions (known working for Rust 1.7).
Say you have a new project as:
src/
main.rs
memory.rs
chunk.rs
In main.rs, you need to annotate that you are importing macros from the source, otherwise, it will not do for you.
#[macro_use]
mod memory;
mod chunk;
fn main() {
println!("Hello, world!");
}
So in memory.rs you can define the macros, and you don't need annotations:
macro_rules! grow_capacity {
( $x:expr ) => {
{
if $x < 8 { 8 } else { $x * 2 }
}
};
}
Finally you can use it in chunk.rs, and you don't need to include the macro here, because it's done in main.rs:
grow_capacity!(8);
The upvoted answer caused confusion for me, with this doc by example, it would be helpful too.
来源:https://stackoverflow.com/questions/63233545/how-do-i-use-rust-macros-in-the-same-crate