Rust 中具有条件编译的相同函数的不同版本

Different versions of the same function with conditional compilation in Rust

我正在尝试创建同一函数的两个不同版本,但只有其中一个会被编译。例如:

#[cfg(debug_assertions)]
fn do_something(x: usize) -> usize {
    x + 1
}

#[cfg(not(debug_assertions))]
fn do_something() -> usize {
    0
}

这很好用,我也可以调用 do_something 的正确版本 如果我知道我在调用哪个 (实际上,函数将执行完全一样,调试只需要更多信息来进行一些验证)。所以我可以创建两个对应的 main 函数:

#[cfg(debug_assertions)]
fn main() {
    do_something(0);
}

#[cfg(not(debug_assertions))]
fn main() {
    do_something();
}

但这很笨拙,我只想拥有一个不依赖于 debug_assertions 的代码版本。我想做类似的事情:

macro_rules! call {
    ($func:ident, $optional_arg:expr) => {{
        if cfg!(debug_assertions) {
            $func($optional_arg);
        } else {
            $func();
        }
    }};
}

fn main() {
    call!(do_something, 0);
}

然后在我调用此函数或类似函数的任何地方重新使用宏。但这不编译:

  --> main.rs:16:13
   |
2  | fn do_something(x: usize) -> usize {
   | ---------------------------------- defined here
...
16 |             $func();
   |             ^^^^^-- supplied 0 arguments

   |             |
   |             expected 1 argument
...
22 |     call!(do_something, 0);
   |     ----------------------- in this macro invocation
   |
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error

我不明白为什么会出现错误,因为甚至不应该编译错误的函数调用。 可以通过强制函数具有相同的签名并简单地忽略发布版本中不必要的参数来修复错误,但这似乎不是正确的方法。

遇到这种情况你会怎么做?为什么宏示例无法编译?

来自reference :

cfg!, unlike #[cfg], does not remove any code and only evaluates to true or false. For example, all blocks in an if/else expression need to be valid when cfg! is used for the condition, regardless of what cfg! is evaluating

标志将在编译时进行评估,但您是在运行时进行此检查。你需要使用属性来避免这个问题:

macro_rules! call {
    ($func:ident, $optional_arg:expr) => {{
        #[cfg(debug_assertions)]
        $func($optional_arg);

        #[cfg(not(debug_assertions))]
        $func();
    }};
}