如何使用num_traits获取任意数值类型字节数以实现Read扩展?
为std::io::Read实现读取任意数值类型的扩展Trait
你需要为std::io::Read实现扩展Trait来读取任意数值类型,但卡在获取类型字节数的编译期常量上,且不能使用nightly特性。以下是两种可行的解决方案:
方案一:直接使用std::mem::size_of(最简洁)
利用std::mem::size_of这个const函数获取类型的字节数,它在编译期就能确定数值类型的大小,直接用于数组初始化:
use num_traits::FromBytes; use std::io::{Read, Result}; use std::mem; pub trait ReadNums: Read { fn read_num_be<N>(&mut self) -> Result<N> where N: FromBytes + Sized, { // 直接用mem::size_of获取编译期常量作为数组长度 let mut buffer = [0; mem::size_of::<N>()]; self.read_exact(&mut buffer)?; Ok(N::from_be_bytes(&buffer)) } } impl<T> ReadNums for T where T: Read {}
mem::size_of::<N>()是编译期求值的const函数,所有数值类型(如i32、u64等)的大小都是固定的编译期常量,因此可以直接用来定义数组长度。Sized约束确保类型有固定大小,而所有实现FromBytes的数值类型都满足这一点。
方案二:自定义Trait提供字节数关联常量(更清晰)
如果希望显式定义字节数的关联常量,可以自定义一个ByteLength Trait,为所有数值类型实现它:
use num_traits::FromBytes; use std::io::{Read, Result}; use std::mem; // 定义获取字节长度的Trait pub trait ByteLength { const LEN: usize; } // 用宏批量为所有数值类型实现ByteLength macro_rules! impl_byte_length { ($($t:ty),*) => { $( impl ByteLength for $t { const LEN: usize = mem::size_of::<$t>(); } )* }; } // 覆盖常见的数值类型 impl_byte_length!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64); pub trait ReadNums: Read { fn read_num_be<N>(&mut self) -> Result<N> where N: FromBytes + ByteLength, { let mut buffer = [0; N::LEN]; self.read_exact(&mut buffer)?; Ok(N::from_be_bytes(&buffer)) } } impl<T> ReadNums for T where T: Read {}
通过自定义ByteLength Trait,将字节数作为关联常量暴露出来,代码可读性更强。宏批量实现避免了重复代码,覆盖了所有常见的数值类型。
内容的提问来源于stack exchange,提问作者user22747722
相关产品推荐
相关产品推荐

