I want to convert a usize
typed variable into a u32
typed variable in Rust. I am aware that the usize
variable might contain a value larger than 2^32, and in that case the conversion should fail. I am trying to use the TryFrom
trait to perform the conversion.
This is a simple example (Nightly Rust, Playground):
#![feature(try_from)]
use std::convert::TryFrom;
fn main() {
let a: usize = 0x100;
let res = u32::try_from(a);
println!("res = {:?}", res);
}
The code doesn't compile, with the following compilation error:
error[E0277]: the trait bound `u32: std::convert::From<usize>` is not satisfied
--> src/main.rs:6:15
|
6 | let res = u32::try_from(a);
| ^^^^^^^^^^^^^ the trait `std::convert::From<usize>` is not implemented for `u32`
|
= help: the following implementations were found:
<u32 as std::convert::From<std::net::Ipv4Addr>>
<u32 as std::convert::From<u8>>
<u32 as std::convert::From<char>>
<u32 as std::convert::From<u16>>
= note: required because of the requirements on the impl of `std::convert::TryFrom<usize>` for `u32`
I deduce from the compilation error that having TryFrom<usize>
for u32
is dependent on having From<usize>
for u32
, which seems somewhat strange to me.
Is there any other way I could utilize TryFrom
to convert from usize
to u32
? If not, is there any other idiomatic way to perform this conversion?
I know that I can use the as
keyword, but it doesn't notify me if something went wrong with the conversion. In addition, I think that I can write my own function that does the conversion, but I would be surprised if Rust doesn't have some idiomatic way to do this conversion. usize
and u32
are two basic types, after all.
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.
Since this answer was created, it was decided to have the implementation of TryFrom<usize>
always allow for the possibility of failure, regardless of the current platform. The original code now compiles successfully in Rust 1.34.
having
TryFrom<usize>
foru32
is dependent on havingFrom<usize>
foru32
, which seems somewhat strange to me
This is because there's a blanket implementation of TryFrom
for anything that implements From
:
impl<T, U> TryFrom<U> for T
where
T: From<U>,
{
type Error = !;
}
As you mentioned, since Rust supports platforms where the native integer length is 16, 32, or 64 bits, having such an implementation of From
/ Into
would not be lossless on some of these platforms.
This error occurs because there's no direct implementation of TryFrom
/ TryInto
for these types. This is because users of these traits prefer that the implementations be infallible when platform-appropriate (The type Error = !
).
There is a separate tracking issue 49415 specifically for deciding this issue.
I think that I can write my own function that does the conversion
Yes, that is what you should do. Something like this untested piece of code:
use std::u32;
struct SomeError;
// usize is a u16 or u32, which always fits in a u32
#[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
fn my_thing(a: usize) -> Result<u32, SomeError> {
Ok(a as u32)
}
// usize is a u64, which might be too big
#[cfg(target_pointer_width = "64")]
fn my_thing(a: usize) -> Result<u32, SomeError> {
if a > u32::MAX as usize {
Err(SomeError)
} else {
Ok(a as u32)
}
}
I would be surprised if Rust doesn't have some idiomatic way to do this conversion.
usize
andu32
are two basic types, after all.
The problem is that usize
isn't really a "basic" type because it changes size depending on the target platform. Getting this correct, performant and ergonomic is not easy.
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