条件编译
条件编译
.NET 与 Rust 都支持基于外部条件编译不同代码路径。
在 .NET 中,通常通过 预处理指令 控制条件编译:
#if debug
Console.WriteLine("Debug");
#else
Console.WriteLine("Not debug");
#endif除了预定义符号外,还可以使用编译器选项 DefineConstants 定义自定义符号,
并配合 #if、#else、#elif、#endif 做条件分支编译。
在 Rust 中,可通过 cfg attribute、cfg_attr attribute
和 cfg! macro 实现条件编译。
和 .NET 类似,Rust 除了预定义条件,也可使用编译参数
--cfg 自定义配置选项。
cfg attribute 需要一个 ConfigurationPredicate 并在编译期求值:
use std::fmt::{Display, Formatter};
struct MyStruct;
// 仅在 unix 且 foo != "bar" 时编译该实现
// 在 Linux 下可通过 rustc main.rs --cfg foo=\"baz\" 编译此分支
#[cfg(all(unix, not(foo = "bar")))]
impl Display for MyStruct {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("Running without foo=bar configuration")
}
}
// 仅在 unix 且 foo == "bar" 时编译该实现
// 在 Linux 下可通过 rustc main.rs --cfg foo=\"bar\" 编译此分支
#[cfg(all(unix, foo = "bar"))]
impl Display for MyStruct {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("Running with foo=bar configuration")
}
}
// 非 unix 平台编译该实现(此处直接 panic)
#[cfg(not(unix))]
impl Display for MyStruct {
fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result {
panic!()
}
}
fn main() {
println!("{}", MyStruct);
}cfg_attr attribute 可以在条件满足时附加属性:
#[cfg_attr(feature = "serialization_support", derive(Serialize, Deserialize))]
pub struct MaybeSerializableStruct;
// 当启用 serialization_support feature 后,上述代码等价于:
// #[derive(Serialize, Deserialize)]
// pub struct MaybeSerializableStruct;内置的 cfg! macro 会在编译期判断条件并产出布尔字面量:
if cfg!(unix) {
println!("I'm running on a unix machine!");
}另见:
特性(Features)
条件编译也常用于“可选依赖”。在 Cargo 中,包可在 Cargo.toml 的 [features]
里定义命名特性,每个特性都可开启/关闭。构建当前包时可通过 --features
在命令行启用;依赖包的特性则可在依赖声明中配置。
另见: