如何跨模块文件使用宏?

问题描述 投票:41回答:3

我在同一个箱子中的两个单独文件中有两个模块,其中箱子启用了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'”...这是有道理的;宏系统在模块系统之前运行。我该如何解决这个问题?

module rust rust-macros
3个回答
78
投票

Macros within the same crate

#[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 {
        () => ()
    }
}

Macros across crates

要使用来自其他包装箱的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]添加到extern crate util;语句来从其他包中导入宏。这将从util导入所有宏。或者,#[macro_use(cat, dog)]可用于仅导入宏catdog。此语法不应该是必要的。)


有关更多信息,请访问The Rust Programming Language


15
投票

从Rust 1.1.0-stable开始,这个答案已经过时了。


你需要在#![macro_escape]的顶部添加macros.rs并使用mod macros;中提到的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

备查,

$ rustc -v
rustc 0.13.0-dev (2790505c1 2014-11-03 14:17:26 +0000)

1
投票

#![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?");
}

您的主要人员会看起来像下面这样:

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关键字访问它们。

© www.soinside.com 2019 - 2024. All rights reserved.