1 个不稳定版本
0.0.1 | 2023年11月21日 |
---|
#87 in #const-generics
22KB
213 行
build_assert
build_assert
允许你在构建时进行断言。
与 assert
以及一些编译时断言的实现(如 static_assertions
)不同,build_assert
在运行前工作,可以用于包含 const 泛型的表达式。
用法
通过运行 cargo add
将 build_assert
添加到您的项目中
cargo add build_assert
示例
fn foo<const N: usize>() {
build_assert!(N > 5);
}
foo::<10>(); // Fine.
foo::<0>(); // Fails to compile.
上面的示例在发布模式下将 无法构建。由于内部实现,它在调试模式下将 通过构建并在运行时恐慌。
相比之下,assert
只会在运行时恐慌,静态断言实现不能应用于 const 泛型
macro_rules! static_assert {
($e:expr) => {
const _: () = core::assert!($e);
};
}
fn foo<const N: usize>() {
static_assert!(N > 5);
}
编译上面的示例时出现错误
error[E0401]: can't use generic parameters from outer item
--> src/lib.rs:36:18
|
9 | fn foo<const N: usize>() {
| - const parameter from outer item
10 | static_assert!(N > 5);
| ^ use of generic parameter from outer item
特性
默认情况下,build_assert
使用内联汇编(即 core::arch::asm
)来引发构建时错误。如果您需要在不支持内联汇编的目标上构建此crate(参见 Rust 参考),您可以启用 no_asm
功能。
当启用 no_asm
时,如果断言失败,build_assert
通过引用一个未定义的符号来引发链接错误。默认情况下,符号名称为 __build_error_impl
。为了避免符号冲突,您可以在构建之前设置环境变量 BUILD_ERROR_SYM
来指定不同的符号
BUILD_ERROR_SYM=hello cargo build --release
请注意,如果项目之前已经构建,则应清除构建缓存以确保此更改生效。
内部原理
build_assert
宏将被展开为
if !cond {
build_error!();
}
在发布模式下,期望优化器评估 if
表达式的条件。如果 cond
是 true
,则 build_error
宏展开的结果将被优化掉。否则,将保留展开结果。
在支持内联汇编的目标上,build_error
宏将展开为
core::arch::asm!("build error at file.rs:line:column");
由于 build
在任何目标上都不是一个有效的指令,因此构建将失败。
在不支持内联汇编的目标上,build_error
宏会展开为
extern "Rust" {
fn __build_error_impl() -> !;
}
unsafe { __build_error_impl() }
可能会出现如下链接错误
error: linking with `cc` failed: exit status: 1
|
= note: env -u ...
= note: /usr/bin/ld: ... .o: in function `rust_out::main::...':
... .rs:6: undefined reference to `__build_error_impl'
collect2: error: ld returned 1 exit status
= note: ...
在调试模式下,由于优化器不会运行,build_error
宏将始终保留。我们无法使用上述方法引发构建错误,否则无论条件是否为 true
,构建都将始终失败。因此,build_error
宏将展开为 panic
。
参考资料
build_assert
宏的灵感来源于 Rust for Linux 项目。此crate使用不同的方法来实现宏。
变更日志
请参阅 CHANGELOG.md。
许可证
版权所有 (C) 2023 MaxXing。根据您的选择,许可协议为 Apache 2.0 或 MIT。
依赖项
~260–710KB
~17K SLoC