Module 如何跨模块文件使用宏?

Module 如何跨模块文件使用宏?,module,rust,rust-macros,Module,Rust,Rust Macros,我在同一个板条箱内有两个单独文件中的模块,其中板条箱启用了macro\u规则。我想在另一个模块中使用在一个模块中定义的宏 // 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

我在同一个板条箱内有两个单独文件中的模块,其中板条箱启用了
macro\u规则
。我想在另一个模块中使用在一个模块中定义的宏

// 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?
//macros.rs
#[宏_导出]//还是不?这是无效的,阿飞
宏规则!我的_宏(…)
//什么东西
使用宏;

//使用宏::my_宏 此答案在Rust 1.1.0-stable中已过时


您需要添加
#![macro_escape]
位于
macros.rs
的顶部,并使用
mod macros将其包括在内如中所述

供日后参考,

$ rustc -v
rustc 0.13.0-dev (2790505c1 2014-11-03 14:17:26 +0000)
同一板条箱内的宏 如果要在同一机箱中使用宏,则定义宏的模块需要属性
#[macro\u use]

宏只有在定义后才能使用。这意味着这不起作用:

bar!();  // ERROR: cannot find macro `bar!` in this scope

#[macro_use]
mod foo {
    macro_rules! bar {
        () => ()
    }
}
跨板条箱的宏 使用您的
宏规则宏从其他板条箱中取出,宏本身需要属性
#[macro_export]
。然后,导入板条箱可以通过
使用板条箱名称::宏名称导入宏

板条箱
util

#[macro_export]
macro_rules! foo {
    () => ()
}
use util::foo;

foo!();
板条箱
用户

#[macro_export]
macro_rules! foo {
    () => ()
}
use util::foo;

foo!();

请注意,宏始终位于板条箱的顶层;因此,即使
foo
将位于
mod bar{}
内,
用户
板条箱仍必须编写
use util::foo而不是
使用util::bar::foo

在Rust 2018之前,您必须通过将属性
#[macro_use]
添加到
外部板条箱util,从其他板条箱导入宏语句。这将从
util
导入所有宏。或者,
#[macro\u use(cat,dog)]
只能用于导入宏
cat
dog
。这种语法应该不再必要了

有关更多信息,请访问。

添加
#![macro\u 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();
}
请注意,一旦使用
mod
将文件拉入main.rs,您的其余文件就可以通过
use
关键字访问这些文件。

我在Rust 1.44.1中使用过,此解决方案适用于更高版本(已知适用于Rust 1.7)

假设您有一个新项目:

src/
    main.rs
    memory.rs
    chunk.rs
main.rs中,您需要注释您正在从源代码导入宏,否则,它将不适用于您

#[宏使用]
mod存储器;
模块块;
fn main(){
println!(“你好,世界!”);
}
因此,在memory.rs中,您可以定义宏,而不需要注释:

macro\u规则!增加容量{
($x:expr)=>{
{
如果$x<8{8}否则{$x*2}
}
};
}
最后,您可以在chunk.rs中使用它,您不需要在此处包含宏,因为它是在main.rs中完成的:

增加容量!(8);
这给我带来了困惑,但也会有帮助。

1.32.0开始的替代方法(2018版)
请注意,虽然宏仍然是最新的,并且工作正常,但是必须记住宏的特殊名称空间规则的想法可能会让一些人感到恼火

事实证明,在2018年版及以后的版本中,由于Rust的版本
1.32.0
,还有另一种方法也能起作用,它的好处是imho使教学更容易(例如,它使
#[宏使用]
过时)。关键思想如下:

mod node;  //We're using node.rs
mod toad;  //Also using toad.rs

fn main() {
    test!();
    best!();
    toad::a_thing();
}
重新导出的宏与任何其他项(函数、类型、常量等)的行为相同:它在重新导出发生的模块内具有名称空间。
  • 然后可以使用完全限定的路径引用它

  • 它也可以本地
    use
    d/纳入范围,以便以不合格的方式引用它

例子
macro\u规则!宏名称{…}
发布(板条箱)使用宏_name;//现在经典路径就可以工作了™
就这样。很简单吧


可以继续阅读,但前提是你不害怕信息过载;)我将尝试详细说明为什么、如何以及何时具体执行此操作

更详细的解释 为了重新导出(
pub(…)使用…
)宏,我们需要参考它!这就是原始答案中的规则很有用的地方:宏总是可以在宏定义出现的模块中命名,但只能在该定义之后命名

macro\u规则!我的_宏{…}
我的天哪!(...); // 好啊
//不正常
我的天哪!(...); /* 错误,范围中没有“my_宏”*/
宏规则!我的_宏{…}

在此基础上,定义后可以重新导出宏;因此,重新导出的名称本身就与位置无关,就像Rust中的所有其他全球项目一样您不能使用
模块::my_宏!()?
nope(不是afaik)-据报道模块前缀被忽略(根据编译器消息)。我完全忽略了该属性。谢谢顺便说一句,
#[macro_export]
属性在这里是不必要的。仅当宏应导出到外部板条箱用户时才需要。如果宏仅在机箱内使用,则不需要使用
#[macro\u export]
。非常感谢您的回答。我只想补充一点,如果您的
something.rs
文件使用了其他模块,例如
mod foobar
,此
foobar
模块使用
macro.rs
中的宏,然后您必须放入
mod macro
mod foobar之前。(注意,这个答案现在已经过时了;