如何在其自身的crate中使用宏?

26

我相信这很容易做到,但我似乎无法使其正常工作。

我查看了http://doc.rust-lang.org/book/advanced-macros.html#scoping-and-macro-import/export,一般来说,使用宏的方法是定义它们:

#[macro_export]
macro_rules! background(($token:expr) => (($token >> (32 + 8)) & $crate::graphics::mask::Color));

然后使用以下方式将它们导入到另一个上下文中:

#[macro_use]
extern crate terminal;
...

然而,我想要做的是在定义宏的包内使用这些宏。

如果我的文件结构如下:

- lib.rs
- macros.rs
- foo
- foo/mod.rs
- foo/junk.rs

我该如何在junk.rs中使用macros.rs中的宏?

我已经尝试过各种组合,例如#[macro_use] mod macros等,但都没有成功。文档建议如果一个宏在某个作用域中定义,则它在所有子模块中都可用...这是否意味着我必须在lib.rs中定义我的宏?

2个回答

73

被接受的答案是正确的,但对于将来发现这个问题的其他人,我想补充一点,即模块加载的顺序很重要。

例如,在以下顺序中:

pub mod terminal;
pub mod terminals;
pub mod graphics;

#[macro_use]
mod macros;
如果终端使用了宏,但是它将不会起作用;必须在使用该宏的任何其他模块之上使用#[macro_use]

如果终端使用了宏,但是它将不会起作用;必须在使用该宏的任何其他模块之上使用#[macro_use]

#[macro_use]
mod macros;

pub mod terminal;
pub mod terminals;
pub mod graphics;

2
这正是我的问题!我希望书中可以突出显示。 - Tomas Tomecek

30

您需要使用#[macro_export]标记您的宏,然后使用#[macro_use]标记模块:

#[macro_use]
mod macros {
    #[macro_export]
    macro_rules! my_macro(() => (42));
}

pub mod foo {
    pub mod junk {
        pub fn usage() -> u8 {
            my_macro!()
        }
    }
}

fn main() {
    println!("{:?}", foo::junk::usage());
}

从技术上讲,只有在您希望宏对您的 crate 的用户可用时才需要使用 #[macro_export]

(Playground 链接)


2
这个在内联中是有效的,但当我尝试使用文件时似乎不行;看一下这个微不足道的例子 https://github.com/shadowmint/rust-starter;它会出现错误 "src/module1/blah.rs:2:15: 2:18 error: macro undefined: 'fmt!'",但是https://raw.githubusercontent.com/shadowmint/rust-starter/master/src/lib.rs 正好做了你说的事情。 - Doug
你所提供的代码中没有 mod module1;,也许错误来自于其他地方? - huon
请参阅:http://doc.rust-lang.org/nightly/book/advanced-macros.html#scoping-and-macro-import/export。 - huon
@huon-dbaupp 哦,你说得对,它需要在 main.rs 文件中。 - Doug
1
值得注意的是,mod macros {} 必须出现在其他依赖于宏的 mod 声明之前。 - E net4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接