如何有条件地更改 Rust 宏的一小部分?

orl*_*rlp 5 macros rust

我正在建造一个具有该功能的板条箱foo。这个板条箱有一个宏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
    }
}
Run Code Online (Sandbox Code Playgroud)

这是很多容易出错的重复。两种不起作用的方法:

  • 我们无法移动cfg宏内部,因为这样它将在板条箱用户的范围内扩展,而该范围没有foo适当设置的功能。

  • 从 Rust 1.30 开始,我们不能使用辅助宏并在辅助宏上#[doc(hidden)] #[macro_export] macro_rules! bar_priv_impl__使用,因为用户现在可以请求仅导入宏,从而给出有关如何未定义的错误。#[cfg]use mycrate::bar;bar!bar_priv_impl__!

有没有比完全宏复制更好的方法?如果您要测试 N 个功能,情况会变得非常糟糕,因为您需要2 n 个重复项。

She*_*ter 3

从 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)
}
Run Code Online (Sandbox Code Playgroud)

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

#[macro_export]
macro_rules! bar {
    ($val:expr) => ($crate::__bar_foo!($val))
}
Run Code Online (Sandbox Code Playgroud)