How do I cast a u64 value to a generic numeric typ

2019-08-10 16:14发布

问题:

I would like to cast a u64 value to a generic numeric type, something like

fn f<T: AppropriateTrait>(v: u64) -> T {
    v as T
}

and have it behave semantically like, e.g., 259u64 as u8, i.e., it should just take the least significant bits. Unfortunately, the FromPrimitive::from_u64 function returns an Option<T>, with None if the input value doesn't fit.

This here works:

fn f<T: FromPrimitive + Int + ToPrimitive>(v: u64) -> T {
    T::from_u64(v & T::max_value().to_u64().unwrap()).unwrap()
}

But it's very verbose and inelegant. Is there a better way?

Edit: I'm only interested in casting to integer types like u8, u16, etc., no funky stuff.

回答1:

One way to do this particularly efficiently is to define your own trait with the desired effect; especially if you are getting to something more complex, this will often be what you desire (though definitely not always). For this case, you might go for something like this:

trait FromU64 {
    fn from_u64(v: u64) -> Self;
}

macro_rules! impl_from_u64 {
    ($($ty:ty)*) => {
        $(
            impl FromU64 for $ty {
                #[inline]
                fn from_u64(v: u64) -> $ty {
                    v as $ty
                }
            }
        )*
    }
}

impl_from_u64!(u8 u16 u32 u64 usize);

Your original f::<T> would then be <T as FromU64>::from_u64, or alternatively

fn f<T: FromU64>(v: u64) -> T {
    FromU64::from_u64(T)
}


标签: rust