把不变量检查从运行期挪到编译期:结构体大小、泛型参数范围……这篇用 const assert、关联常量和 inline const 块验证它们什么时候求值、报什么错、有没有运行期成本。
源码:
1 | #[repr(C)] struct Header { tag: u8, len: u32 }
2 | const _: () = assert!(std::mem::size_of::<Header>() == 8, "Header 必须是 8 字节");
3 | fn main() { println!("size = {}", std::mem::size_of::<Header>()); }
编译:成功
运行(退出码 0):
size = 8
源码:
1 | #[repr(C)] struct Header { tag: u8, len: u32 }
2 | const _: () = assert!(std::mem::size_of::<Header>() == 6, "Header 必须是 6 字节");
3 | fn main() { println!("size = {}", std::mem::size_of::<Header>()); }
编译:失败
error[E0080]: evaluation panicked: Header 必须是 6 字节
--> <实验目录>/src/u84b.rs:2:15
|
2 | const _: () = assert!(std::mem::size_of::<Header>() == 6, "Header 必须是 6 字节");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0080`.有 const 断言的 f 汇编 2 行,没有断言的 2 行,逐行相同: True
源码:
1 | struct Buf<const N: usize>;
2 | impl<const N: usize> Buf<N> {
3 | const OK: () = assert!(N.is_power_of_two(), "N 必须是 2 的幂");
4 | fn new() -> Self { let () = Self::OK; Buf }
5 | }
6 | fn main() { let _a = Buf::<8>::new(); println!("Buf::<8> 创建成功"); }
编译:成功
运行(退出码 0):
Buf::<8> 创建成功
源码:
1 | struct Buf<const N: usize>;
2 | impl<const N: usize> Buf<N> {
3 | const OK: () = assert!(N.is_power_of_two(), "N 必须是 2 的幂");
4 | fn new() -> Self { let () = Self::OK; Buf }
5 | }
6 | fn main() { let _a = Buf::<8>::new(); let _b = Buf::<6>::new(); }
编译:失败
error[E0080]: evaluation panicked: N 必须是 2 的幂
--> <实验目录>/src/u84e.rs:3:20
|
3 | const OK: () = assert!(N.is_power_of_two(), "N 必须是 2 的幂");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Buf::<6>::OK` failed here
note: erroneous constant encountered
--> <实验目录>/src/u84e.rs:4:33
|
4 | fn new() -> Self { let () = Self::OK; Buf }
| ^^^^^^^^
note: the above error was encountered while instantiating `fn Buf::<6>::new`
--> <实验目录>/src/u84e.rs:6:48
|
6 | fn main() { let _a = Buf::<8>::new(); let _b = Buf::<6>::new(); }
| ^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0080`. 源码:
1 | fn first_n<const N: usize>() -> [u8; N] { const { assert!(N > 0 && N <= 4, "N 必须在 1..=4") }; [0; N] }
2 | fn main() { println!("{:?}", first_n::<3>()); }
编译:成功
运行(退出码 0):
[0, 0, 0]
源码:
1 | fn first_n<const N: usize>() -> [u8; N] { const { assert!(N > 0 && N <= 4, "N 必须在 1..=4") }; [0; N] }
2 | fn main() { println!("{:?}", first_n::<9>()); }
编译:失败
error[E0080]: evaluation panicked: N 必须在 1..=4
--> <实验目录>/src/u84g.rs:1:51
|
1 | fn first_n<const N: usize>() -> [u8; N] { const { assert!(N > 0 && N <= 4, "N 必须在 1..=4") }; [0; N] }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `first_n::<9>::{constant#1}` failed here
note: erroneous constant encountered
--> <实验目录>/src/u84g.rs:1:43
|
1 | fn first_n<const N: usize>() -> [u8; N] { const { assert!(N > 0 && N <= 4, "N 必须在 1..=4") }; [0; N] }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: the above error was encountered while instantiating `fn first_n::<9>`
--> <实验目录>/src/u84g.rs:2:30
|
2 | fn main() { println!("{:?}", first_n::<9>()); }
| ^^^^^^^^^^^^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0080`. 源码:
1 | const _: [(); 0 - (std::mem::size_of::<u32>() != 4) as usize] = [];
2 | const _: [(); 0 - (std::mem::size_of::<u32>() != 5) as usize] = [];
3 | fn main() {}
编译:失败
error[E0080]: attempt to compute `0_usize - 1_usize`, which would overflow
--> <实验目录>/src/u84h.rs:2:15
|
2 | const _: [(); 0 - (std::mem::size_of::<u32>() != 5) as usize] = [];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_::{constant#0}` failed here
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0080`.布局相关的例子见Struct 对齐与 Padding。