【问题标题】:How to use macros from re-exported crates如何使用重新导出的 crate 中的宏
【发布时间】:2018-04-26 07:21:31
【问题描述】:

Crate 可以重新导出它们所依赖的 crate。在此示例中,stm32f103xx-hal 板条箱执行以下操作:pub extern crate stm32f103xx;

在我的代码中,我依赖于stm32f103xx-hal。现在我想使用由stm32f103xx crate 导出的interrupt!() 宏。我是否必须在我的 Cargo.toml 中添加 stm32f103xx crate 依赖项,还是有办法重新使用导出的 stm32f103xx-hal 定义?

请注意,这与简单的“如何使用来自不同 crate 的宏”是不同的问题。在stm32f103xx-hal 上声明#[macro_use(interrupt)] 会产生cannot find macro 'interrupt!' in this scope 错误。

【问题讨论】:

标签: macros rust


【解决方案1】:

我认为您需要将stm32f103xx 添加到您的Cargo.toml。原因如下:

例如在柴油机lib.rs

#[macro_use]
extern crate diesel_derives;
#[doc(hidden)]
pub use diesel_derives::*;

他们将#[macro_use] 放在extern crate 行,然后使用diesel_derives 项目中的所有内容。

在您的情况下,lib.rs 看起来像这样:

pub extern crate stm32f103xx;

所以重新导出并没有指定使用宏。

这就是为什么您需要将stm32f103xx 添加到您的 Cargo.toml 以便在您自己的lib.rs 中指定宏的使用。

【讨论】:

  • 这是有道理的,尽管这样设计 Cargo 似乎有点脆弱。谢谢。
  • @MichaelBöckling 什么是“脆弱”?您正在使用的 crate 选择不(或忘记)导出宏。你想让 Cargo 怎么做?忽略编写的代码,随意引入任何感觉?
  • 好吧,他们可能会忘记导出宏。 crate 已经决定了它的公共 API 表面,为什么另一个重新导出它的 crate 对此事有任何发言权?
  • @MichaelBöckling 因为他们选择重新导出的内容成为他们的 API 表面的一部分。
  • 但是当重新导出的 crate 是 optional=true 并通过功能(和 pub use)来时,重新导出到 #[macro_use] 是不可能的?
【解决方案2】:

中间板条箱应该重新导出宏以便它们可用:

mac/src/lib.rs

#[macro_export]
macro_rules! a_macro {
    () => (42);
}

inter/src/lib.rs

pub extern crate mac;
pub use mac::*; // Re-export the macros

ex/src/main.rs

#[macro_use]
extern crate inter;

fn main() {
    println!("Hello, {}", a_macro!());
}

在您的情况下,这要么是库的错误,要么是他们故意决定不重新导出它们,因此您需要与他们一起处理。您可以选择直接依赖底层的 crate,但随后您会发现 crate 的版本不匹配,从而导致恼人的错误。

【讨论】:

  • Shepmaster 在这里提出了一个很好的观点。在您的情况下,即使板条箱 stm32f103xx-hal 会从 stm32f103xx 重新导出宏,最好还是明确导入 stm32f103xx 以允许您指定所需的版本。
  • @KimDesrosiers 我相信你已经完全理解了我。我是说同时依赖重新导出的板条箱和直接依赖板条箱是一个 的想法,因为会发生版本不兼容。您应该只使用重新导出的代码(不能使用,因为它当前没有导出宏)。 不是“显式导入 stm32f103xx 的最佳做法”,因为您无法控制 stm32f103xx-hal 使用的版本。
  • 我把最后一句话读得太快了,我的错。但是,也许这不是一个好习惯,但在当前情况下,我们没有选择是否要使用宏。是否可以在同一个项目中使用两个不同版本的 crate?我的意思是我们可以在需要的地方为重新导出使用别名并使用 Cargo.toml 中的另一个吗?
  • @KimDesrosiers 如果您的意思是“当前情况”作为这两个特定箱子现在的状态,那么是的,您必须直接和间接地包含箱子,这对您自己的未来不利。这就是为什么我鼓励 OP 向 crate(s) 提出问题。 AFAIK,你不能在 Cargo.toml 中指定同一个 crate 的两个版本,但你当然可以在整个 crate 依赖图中有多个版本的 crate。具体例子见Why is a trait not implemented for a type that clearly has it implemented?
  • 明确提出问题是正确的做法。
【解决方案3】:

最近才更改为使用通用导入系统。

假设您想使用 foocrate 中的 interrupt! 宏,新的方法如下所示:

#![feature(use_extern_macros)];

pub use foo::interrupt;

请注意,这还不稳定,所以它在use_extern_macros 后面被功能控制。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-10
    • 2019-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多