What's the idiomatic way to convert from (say) a usize
to a u32
?
For example, casting using 4294967295us as u32
works and the rust reference docs on type casting say
A numeric value can be cast to any numeric type. A raw pointer value can be cast to or from any integral type or raw pointer type. Any other cast is unsupported and will fail to compile.
but 4294967296us as u32
will silently overflow and give a result of 0.
I found ToPrimitive and FromPrimitive which provide nice functions like to_u32() -> Option<u32>
, but they're currently marked as unstable:
#[unstable(feature = "core", reason = "trait is likely to be removed")]
What's the idiomatic (and safe) way to convert between numeric (and pointer) types?
Update: the variable size of isize
/usize
is one reason why I'm asking this question - the original scenario was I wanted to convert from u32
to usize
so I could represent a tree in a Vec<u32>
(e.g. let t = Vec![0u32, 0u32, 1u32]
, then to get the grand-parent of node 2 would be t[t[2us] as usize]
), and I wondered how it would fail if usize
was less than 32 bits.
On ToPrimitive
The RFC states:
Ideally [...] ToPrimitive [...] would all be removed in favor of a more principled way of working with C-like enums
So it seems like this trait is mostly viewed as something for C interop and not just size-changing. Perhaps you could file another RFC or ask on the users forum or subreddit or IRC to see about keeping it.
Dealing without it
Let's say that ToPrimitive
disappears. I'd suggest checking to see if a crate pops up with the same functionality. If not, you could create one by copying the existing functionality. The general outline of that functionality follows.
If you are casting from a smaller type to a larger type, then there's no problem. Your question really centers around going from a larger type to a smaller one.
I don't think there is a single method that makes general sense - you are asking how to fit two things in a space meant for one. In certain cases this should be a fatal error. In other cases, maybe you have a second code path to take. Here's how to use the MAX constants to check though:
fn main() {
let a: u64 = 4294967295;
//let a: u64 = 4294967296;
let b = if a > std::u32::MAX as u64 {
None
} else {
Some(a as u32)
};
println!("{} -> {}", a, b.unwrap());
}
but 4294967296us as u32 will silently overflow and give a result of 0
To clarify, as
just takes the lower bits of the number:
fn main() {
let a: u16 = 0x1234;
let b: u8 = a as u8;
println!("0x{:04x}, 0x{:02x}", a, b)
// 0x1234, 0x34
}