使用typenum在Rust中实现静态边界检查的编译错误求助
解决ByteSliceReader编译期边界检查的typenum约束问题
问题核心
调用pop::<1>时编译报错,是因为辅助函数get_serial_and_part_num的泛型约束没有覆盖pop方法所需的全部条件——不仅要保证Cursor能和U1相加,还要确保相加后的光标位置不超过缓冲区长度。
修改后的辅助函数代码
use typenum::*; fn get_serial_and_part_num<const LEN: usize, Cursor>( reader: ByteSliceReader<'_, LEN, Cursor>, ) -> (ByteSliceReader<'_, LEN, Sum<Sum<Cursor, U1>, U1>>, (u8, u8)) where Cursor: Unsigned + core::ops::Add<U1>, // 第一次pop后的光标需要满足的约束 Sum<Cursor, U1>: Unsigned + core::ops::Add<U1> + IsLessOrEqual<U<LEN>>, // 第二次pop后的光标需要满足的约束 Sum<Sum<Cursor, U1>, U1>: IsLessOrEqual<U<LEN>>, U<LEN>: Unsigned, { let (reader, serial_num) = reader.pop::<1>(); let (reader, part_num) = reader.pop::<1>(); (reader, (serial_num[0], part_num[0])) }
错误原因解析
原代码的约束只声明了Cursor可以和U1相加,以及相加结果能继续相加,但缺少了光标位置不超过缓冲区长度的IsLessOrEqual约束——这是pop方法要求的核心边界检查条件。编译器无法自动推导这些约束,必须显式声明。
另外,Const<LEN>: ToUInt和Const<1>: ToUInt可以省略,因为typenum对任意合法的usize常量都会自动实现ToUInt trait,返回对应的U<N>类型。
简化impl块约束(可选优化)
原ByteSliceReader的impl块里的Const<LEN>: ToUInt和U<LEN>: Unsigned约束是冗余的,可以直接移除,让代码更简洁:
impl<'a, const LEN: usize, Cursor: Unsigned> ByteSliceReader<'a, LEN, Cursor> { #[must_use] fn pop<const NUM: usize>(self) -> (ByteSliceReader<'a, LEN, Sum<Cursor, U<NUM>>>, [u8; NUM]) where Cursor: core::ops::Add<U<NUM>>, Sum<Cursor, U<NUM>>: IsLessOrEqual<U<LEN>>, { let mut byte_window = [0; NUM]; for (i, byte) in byte_window.iter_mut().enumerate() { *byte = self.buffer[Cursor::to_usize() + i]; } ( ByteSliceReader { buffer: self.buffer, cursor: core::marker::PhantomData, }, byte_window, ) } }
关键注意点
每次调用pop::<NUM>时,都需要确保:
- 当前
Cursor类型支持与U<NUM>相加(Cursor: Add<U<NUM>>) - 相加后的新光标位置不超过缓冲区总长度(
Sum<Cursor, U<NUM>>: IsLessOrEqual<U<LEN>>) - 如果后续还要调用
pop,新的光标类型也要满足上述两个条件
内容的提问来源于stack exchange,提问作者Josh Burkart
相关产品推荐
相关产品推荐

