具有任意常量表达式的 cfg 属性

cfg attribute with arbitrary constant expression

我有以下常量:

const IS_WSL: bool = is_wsl!();

我希望能够将其与 cfg 属性一起使用来执行条件编译。类似于:

#[cfg(const = "IS_WSL")]  // what goes here?
const DOWNLOLADS: &'static str = "/mnt/c/Users/foo/Downloads";

#[cfg(not(const = "IS_WSL"))]
const DOWNLOADS: &'static str = "/home/foo/Downloads";

显然这个语法不起作用,但是有什么方法可以实现我所描述的吗?

我知道自定义 rustc 标志,但我想避免这样做,因为有相当多的逻辑我不想尝试在 bash

中编写

答案是否定的。您必须使用构建脚本之类的东西来实现。

它无法工作,因为 cfg- 扩展发生在编译器中比常量评估更早的阶段。

cfg 扩展与宏扩展同时工作。两者都会影响名称解析(宏可以创建新名称,其他宏甚至同一个宏以后可以引用)这迫使我们使用 fixed-point 算法(解析名称、扩展宏、解析名称、扩展宏...直到无法解析更多名称,即达到固定点)。 const 评估在类型检查之后进行,有时(使用 generic_const_exprs)甚至在代码生成期间。如果它能影响宏扩展,我们将有一个巨大的 fixed-point 循环解析名称 - 扩展宏 - 解析名称 - 扩展宏...直到达到固定点,然后降低到 HIR - type-check -评估常量(或什至低于 MIR - 单态化和评估常量) - 并返回名称解析。除了大大降低编译器速度外,它还会使编译器变得更加复杂,这并不是 rustc 团队真正想要的。

在您的特定情况下,由于两个 cfg 变体都声明了具有相同名称和类型的静态,您可以只匹配 IS_WSL:

const IS_WSL: bool = is_wsl!();

const DOWNLOADS: &'static str = match IS_WSL {
    true => "/mnt/c/Users/foo/Downloads",
    false => "/home/foo/Downloads",
};

Playground

这与 cfg 的功能不同,但如果您只需要 select 两个相同类型的值,它仍然有用。