#085 Apr 16, 2026

85. cast_signed & cast_unsigned — Explicit Sign Casting for Integers

Stop using as to flip between signed and unsigned integers — cast_signed() and cast_unsigned() say exactly what you mean.

The problem with as

When you write value as u32 or value as i64, the as keyword does too many things at once: it can change the sign, widen, truncate, or even convert floats. Readers have to mentally verify which conversion is actually happening.

1
2
let x: i32 = -1;
let y = x as u32;  // Sign cast? Truncation? Widening? All of the above?

The fix: cast_signed() and cast_unsigned()

Stabilized in Rust 1.87, these methods only reinterpret the sign of an integer — same bit width, same bits, just a different type. If you accidentally try to change the size, it won’t compile.

1
2
3
4
5
6
let signed: i32 = -1;
let unsigned: u32 = signed.cast_unsigned();
assert_eq!(unsigned, u32::MAX); // Same bits, different interpretation

let back: i32 = unsigned.cast_signed();
assert_eq!(back, -1); // Round-trips perfectly

The key constraint: these methods only exist between same-sized pairs (i32u32, i64u64, etc.). There’s no i32::cast_unsigned() returning a u64 — that would silently widen, which is exactly the kind of ambiguity these methods eliminate.

Where this shines

Bit manipulation is the classic use case. When you need to treat an unsigned value as signed for arithmetic and then go back, the intent is crystal clear:

1
2
3
4
5
6
fn wrapping_distance(a: u32, b: u32) -> i32 {
    a.wrapping_sub(b).cast_signed()
}

assert_eq!(wrapping_distance(10, 3), 7);
assert_eq!(wrapping_distance(3, 10), -7);

Compare that to the as version — a.wrapping_sub(b) as i32 — and you can see why reviewers love the explicit method. It’s one less thing to second-guess in a code review.

← Previous 84. Result::flatten — Unwrap Nested Results in One Call Next → 86. cfg_select! — Compile-Time Match on Platform and Features