【问题标题】:What is the proper way to use the `cfg!` macro to choose between multiple implementations?使用“cfg!”宏在多个实现之间进行选择的正确方法是什么?
【发布时间】:2018-01-07 16:33:10
【问题描述】:

我在Cargo.toml中指定了一些特性:

[features]
complex = []
simple = []

当我构建我的项目时,我使用cargo build --features="complex"simple

在某些函数中,我想根据使用的功能返回一个值:

fn test() -> u32 {
    let x: u32 = 3;
    if cfg!(feature = "complex") {
        let y: u32 = 2;
        x + y
    }
    if cfg!(feature = "simple") {
        let y: u32 = 1;
        x + y
    }
}

但这不起作用,因为它试图评估两个表达式。在我的情况下,使用 cfg! 宏的正确方法是什么?

【问题讨论】:

  • Idiomatic Rust 不使用冗余类型注释。应删除函数体内的所有: u32

标签: rust


【解决方案1】:

documentation for cfg! 声明:

配置标志的布尔评估。

这意味着 cfg!(...) 被替换为布尔值 (true / false)。您的代码在展开后将如下所示:

fn test() -> u32 {
    let x = 3;
    if true {
        let y = 2;
        x + y
    }
    if true {
        let y = 1;
        x + y
    }
}

最简单的解决方案是添加else

fn test() -> u32 {
    let x = 3;
    if cfg!(feature = "complex") {
        let y = 2;
        x + y
    } else {
        let y = 1;
        x + y
    }
}

你也可以使用cfg的属性形式。在这种情况下,该属性可以阻止整个 next 表达式被编译:

fn test() -> u32 {
    let x: u32 = 3;

    #[cfg(feature = "complex")]
    {
        let y: u32 = 2;
        x + y
    }

    #[cfg(feature = "simple")]
    {
        let y: u32 = 1;
        x + y
    }
}

因为它试图评估这两个表达式。

不,它没有。评估发生在运行时,甚至无法编译此代码。

另见:

【讨论】:

  • "评估发生在运行时,甚至无法编译此代码。" - 好吧,如果将falsetrue 放在cfg!(feature = "complex") 下的决定是在编译时完成的,那么是什么阻止了编译器/优化器完全删除这些分支(if false,因为它无法访问并且if true因为没有意义)。因此,在运行时根本不会进行评估。
  • @VictorPolevoy 你是对的——if falseif true 应该在编译时删除,至少在优化时是这样。 if false 的主体应该被删除,但 if true 的主体应该被保留。然后将在运行时评估 true 的任何块。这是使用else 的另一个原因——防止both 功能的代码块被评估!另请注意,此类优化不应改变程序的行为。
  • @Shepmaster 这就是我的意思 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-06
  • 2018-08-12
  • 1970-01-01
相关资源
最近更新 更多