【问题标题】:How to conditionally change a small part of a Rust macro?如何有条件地更改 Rust 宏的一小部分?
【发布时间】:2018-10-26 22:48:53
【问题描述】:

我正在构建一个具有foo 功能的板条箱。这个 crate 有一个宏 bar!,它会根据是否设置了 foo 来做一些微妙的不同的事情。

我可以复制整个宏:

#[cfg(feature = "foo")]
macro_rules! bar {
    // Lots of rules...

    ( A ) => {
        B
    }
}

#[cfg(not(feature = "foo"))]
macro_rules! bar {
    // Lots of rules...

    ( A ) => {
        C
    }
}

这是很多容易出错的重复。两种行不通的方法:

  • 我们不能在宏内部移动cfg,因为那样它会在没有适当设置foo 功能的 crate 用户范围内扩展。

  • 自 Rust 1.30 起,我们不能使用 #[doc(hidden)] #[macro_export] macro_rules! bar_priv_impl__ 辅助宏并在辅助宏上使用 #[cfg],因为用户现在可以请求 use mycrate::bar; 仅导入 bar! 宏,给出关于bar_priv_impl__! 怎么没定义。

有没有比完全复制宏更好的方法?如果您有 N 个要测试的功能,那就太糟糕了,因为您需要 2n 个重复。

【问题讨论】:

  • 只导入 bar! — FWIW,以前人们可以通过 #[macro_use(foo, bar)] 做到这一点。
  • @Shepmaster 不,我尝试在那里使用#[cfg] 作为动词。我改写了。

标签: macros rust


【解决方案1】:

自 Rust 1.30 [...] 因为用户现在 [...] 只能导入 bar!

实际上,这种解决方案在 Rust 1.30 中是可行的,因为它能够像正常一样导入宏。请记住,您的宏也可以包含use 语句!:

#[macro_export]
macro_rules! bar {
    ($val:expr) => {{
        use $crate::__bar_foo;
        __bar_foo!($val)
    }}
}

#[cfg(feature = "foo")]
#[macro_export]
macro_rules! __bar_foo {
    ($val:expr) => ($val + 1)
}

#[cfg(not(feature = "foo"))]
#[macro_export]
macro_rules! __bar_foo {
    ($val:expr) => ($val - 1)
}

您还可以完全限定您的辅助宏调用:

#[macro_export]
macro_rules! bar {
    ($val:expr) => ($crate::__bar_foo!($val))
}

【讨论】:

    猜你喜欢
    • 2015-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-26
    • 1970-01-01
    • 1970-01-01
    • 2021-12-26
    • 2020-06-06
    相关资源
    最近更新 更多