Editor's note: This question is from a version of Rust prior to 1.0 and references some items that are not present in Rust 1.0. The answers still contain valuable information.
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 0.12 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 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?
The platform-dependent 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.
usize is the type of Unsigned integers in rust; they meant to deal with integers in rust. Also, they allow positive integers only. we have several types available for unsigned integers, out of which usize is one of them, it stores the integer, or we can say its size in the form of an arch.
There's no problem here. Use the From
trait to be explicit that there's no loss occurring:
fn example(v: i8) -> i32 { i32::from(v) // or v.into() }
You could choose to use as
, but it's recommended to avoid it when you don't need it (see below):
fn example(v: i8) -> i32 { v as i32 }
There isn't a single method that makes general sense - you are asking how to fit two things in a space meant for one. One good initial attempt is to use an Option
— Some
when the value fits and None
otherwise. You can then fail your program or substitute a default value, depending on your needs.
Since Rust 1.34, you can use TryFrom
:
use std::convert::TryFrom; fn example(v: i32) -> Option<i8> { i8::try_from(v).ok() }
Before that, you'd have to write similar code yourself:
fn example(v: i32) -> Option<i8> { if v > std::i8::MAX as i32 { None } else { Some(v as i8) } }
The range of numbers isize
/ usize
can represent changes based on the platform you are compiling for. You'll need to use TryFrom
regardless of your current platform.
See also:
as
doesbut
4294967296us as u32
will silently overflow and give a result of 0
When converting to a smaller type, as
just takes the lower bits of the number, disregarding the upper bits, including the sign:
fn main() { let a: u16 = 0x1234; let b: u8 = a as u8; println!("0x{:04x}, 0x{:02x}", a, b); // 0x1234, 0x34 let a: i16 = -257; let b: u8 = a as u8; println!("0x{:02x}, 0x{:02x}", a, b); // 0xfeff, 0xff }
See also:
ToPrimitive
/ FromPrimitive
RFC 369, Num Reform, states:
Ideally [...]
ToPrimitive
[...] would all be removed in favor of a more principled way of working with C-like enums
In the meantime, these traits live on in the num crate:
ToPrimitive
FromPrimitive
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With