rust 为trait实现一个泛型函数,它可以对不同的数字类型进行操作

wfypjpf4  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(102)

有没有更好的方法来实现原始数字类型的通用转换函数?我一直在努力创建一个更通用的trait版本,它将LE字节流转换为特定类型,然后返回一个选项float 64。(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!");
}

字符串

nbnkbykc

nbnkbykc1#

这可能是一个很好的宏候选者。你可以通过编写一个trait来处理这种情况,然后使用一个宏在几个类型之间执行实现。例如:

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())
    );
}

字符串
Playground
请注意,这里的术语foo是这种字节流的应用程序特定名称的占位符,我建议在应用程序中将其替换为适当的名称。

相关问题