如何从同一 crate 中的不同模块导入/使用宏?

4
现实生活场景:

我想在crate::app::args::parse模块内使用crate::app::verbose_trace!("string literal")

可重现的场景:

经过一个小时的尝试,我得出了以下简单示例。它揭示了我对宏的误解。

  #[macro_use]
  mod foo{
      pub fn bar(){
          println!("bar works")
      }
      #[macro_export]
      macro_rules! baz{
          ()=> {println!("baz works")}
      }
  }

  fn main(){
      foo::bar();
      foo::baz!();
      // Following doesn't work either:
      // use foo::baz;
      // baz!();
  }

编译器报错

  error[E0433]: failed to resolve: could not find `baz` in `foo`
  --> src\main.rs:14:14
  |
  14 |         foo::baz!();
  |              ^^^ could not find `baz` in `foo`

好像它完全盲目 :0

我阅读了:
我想看到:
  • 一个可编译的版本的我的示例。
  • 为什么它无法编译的解释。
  • 可选的:
    • 关于如何在子模块/超模块中使用宏的其他建议。
1个回答

7

#[macro_export]导出宏在crate根目录下。因此,crate::baz!()可以正常工作,但foo::baz!()不行(不需要使用#[macro_use],这是为了在其他crate中使用宏)。

如果要在本路径中导出宏,则完全不需要使用#[macro_export],而是像这样导出宏:

macro_rules! baz {
    () => {
        println!("baz works")
    };
}
pub(crate) use baz;

为了将宏导出以供其他板条箱使用,仍需要使用#[macro_export]
#[macro_export]
macro_rules! baz {
    () => {
        println!("baz works")
    };
}
pub use baz;

这将同时将宏导出到包根和foo下。


有没有一种方法可以避免从箱根导出,而是以其他包可以使用的方式从当前模块导出?我有一个场景,在箱根导出会导致几个模块之间发生冲突。 - Sam Johnson
1
@SamJohnson,不幸的是不能使用macro_rules(只能使用宏2.0)。但是你可以使用一个技巧:导出一个带有 #[doc(hidden)] 混淆名称的宏(比如 module__macro),然后从模块重新导出具有公共名称的宏。 - Chayim Friedman
1
@SamJohnson 例如:#[macro_export] #[doc(hidden)] macro_rules! foo__bar { ... } pub use foo_bar as bar; - Chayim Friedman

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