是否有更好的方法来实现基本数字类型的通用转换函数?我一直在努力创建一个更通用的特征版本,它将 LE 字节流转换为特定类型,然后返回一个选项 float64。在此例程中,如果某个数字的具体类型为max Positive或max(positive-1),则无效。看起来这应该可以通过一个采用泛型并使用 where 子句的函数来实现,但我还没有找到一个可行的解决方案。
struct U16([u8;2]);
struct U32([u8;4]);
struct I16([u8;2]);
struct I32([u8;4]);
trait CanNumber {
fn to_number(&self) -> Option<f64>;
}
impl CanNumber for U16 {
fn to_number(&self) -> Option<f64> {
type nt = u16;
let num: nt = nt::from_le_bytes(self.0);
if (num == nt::MAX) | (num == (nt::MAX-1)) {
None
}
else {
Some(num as f64)
}
}
}
impl CanNumber for I16 {
fn to_number(&self) -> Option<f64> {
type nt = i16;
let num: nt = nt::from_le_bytes(self.0);
if (num == nt::MAX) | (num == (nt::MAX-1)) {
None
}
else {
Some(num as f64)
}
}
}
fn main() {
let test0: f64 = U16([1,2]).to_number().unwrap();
let test1: f64 = I16([1,2]).to_number().unwrap();
println!("test!");
}
这可能是一个很好的宏候选者。您可以通过编写一个特征,然后使用宏跨多种类型执行实现来处理这种情况。例如:
trait FromFooLittleEndian {
type Bytes;
type Number;
fn from_foo_little_endian(bytes: Self::Bytes) -> Option<Self::Number>;
}
macro_rules! impl_from_little_endian {
( $( $ty:path, $bytes:literal );* $( ; )? ) => {
$(
impl FromFooLittleEndian for $ty {
type Bytes = [u8; $bytes];
type Number = $ty;
fn from_foo_little_endian(bytes: Self::Bytes) -> Option<Self::Number> {
let num = <$ty>::from_le_bytes(bytes);
(num < <$ty>::MAX - 1).then_some(num)
}
}
)*
};
}
impl_from_little_endian!(
u16, 2;
i16, 2;
u32, 4;
i32, 4;
u64, 8;
i64, 8;
);
#[test]
fn foo_little_endian() {
assert_eq!(Some(42), u16::from_foo_little_endian(42u16.to_le_bytes()));
assert_eq!(None, u16::from_foo_little_endian(u16::MAX.to_le_bytes()));
assert_eq!(
None,
u16::from_foo_little_endian((u16::MAX - 1).to_le_bytes())
);
assert_eq!(
Some(u16::MAX - 2),
u16::from_foo_little_endian((u16::MAX - 2).to_le_bytes())
);
}
(游乐场)
请注意,此处的术语
foo
是此类字节流的应用程序特定名称的占位符,我建议在您的应用程序中将其替换为适当的名称。