If I try to substract into the negative from an usize integer rust panics.
fn main() {
let a: usize = 1;
println!("{}", a - 5);
}
error: this arithmetic operation will overflow
But I can cast an i32
to usize
and get an overflow without any warnings or errors:
fn main() {
let a: i32 = -1;
let b: usize = a as usize;
println!("{}", b);
}
18446744073709551615
Is there a better way to casting this? I'll just avoid casting i32
to usize
or check manually for overflows, but it is surprising to me that I can get this overflow so easily in Rust.
as
between integer types doesn't do any checks, it just reinterprets the same bytes as different types, truncating or zero/sign extending if needed (meaning overflow when the value is too large or too small). See the Reference for the exact details.
This (as
being unsafe) is one of the reasons that as
is recommended against, and is slowly replaced by other, safer things (the other reason being as
doing too many different things).
The alternative for as
as integer cast is to use From
/Into
and TryFrom
/TryInto
. From
and Into
are implemented between integers when the cast is lossless (an integer, signed or unsigned, to a bigger integer type). TryFrom
/TryInto
are used when there may be a loss in precision (conversions to smaller type or same size with different unsignedness) or when the size is unknown (any integer except u8
and u16
to usize
and likewise, any integer except i8
and i16
to isize
). They will return an error if the value doesn't fit.
So replace your conversion with isize::try_from(a).unwrap()
(or gracefully handle the error).