When working with numeric types in Rust, you'll often need to convert between different integer sizes (like i32 to i64) or perform arithmetic that might overflow. While Rust's as keyword provides basic casts, it can silently truncate or wrap values, leading to subtle bugs. The standard library provides safer alternatives.
Rust's TryFrom and TryInto traits allow fallible conversions that return Result instead of silently changing values:
use std::convert::TryFrom;
let big: i64 = 1000;
let small: Result<i16, _> = i16::try_from(big); // Ok(1000)
let too_big: i64 = 100_000;
// Err(...)
let overflow: Result<i16, _> = i16::try_from(too_big);Rust integers provide methods for safe arithmetic that handle overflow explicitly:
Checked operations return Option<T>, giving None on overflow:
let x: u8 = 250;
assert_eq!(x.checked_add(10), None); // Would overflow
assert_eq!(x.checked_add(5), Some(255));Saturating operations clamp at the type's bounds:
let x: u8 = 250;
assert_eq!(x.saturating_add(10), 255); // Clamped to max
assert_eq!(x.saturating_sub(255), 0); // Clamped to minWrapping operations wrap around on overflow (like C behavior):
let x: u8 = 250;
assert_eq!(x.wrapping_add(10), 4); // 260 wraps to 4Implement the following functions to demonstrate safe numeric conversions and arithmetic:
safe_i32_to_i16(value: i32) -> Option<i16>
i32 to i16, returning None if the
value doesn't fit.safe_u64_to_u32(value: u64) -> Option<u32>
u64 to u32, returning None if the
value doesn't fit.safe_i64_to_usize(value: i64) -> Option<usize>
i64 to usize, returning None if
the value is negative or too large.checked_multiply(a: i32, b: i32) -> Option<i32>
i32 values, returning None on
overflow.checked_power(base: u32, exp: u32) -> Option<u32>
base^exp, returning None on overflow.saturating_sum(numbers: &[i32]) -> i32
i32::MIN or i32::MAX).wrapping_factorial(n: u32) -> u32
n! using wrapping arithmetic
(allows overflow to wrap around).safe_average(numbers: &[i64]) -> Option<i64>
None if the sum would overflow or the slice
is empty.// Safe conversions
assert_eq!(safe_i32_to_i16(1000), Some(1000));
assert_eq!(safe_i32_to_i16(100_000), None);
// Checked arithmetic
assert_eq!(checked_multiply(1000, 1000), Some(1_000_000));
// Overflow
assert_eq!(checked_multiply(100_000, 100_000), None);
// Saturating arithmetic
assert_eq!(saturating_sum(&[i32::MAX, 1]), i32::MAX);
assert_eq!(saturating_sum(&[i32::MIN, -1]), i32::MIN);
// Wrapping arithmetic
assert_eq!(wrapping_factorial(5), 120);
// Wrapped value
assert_eq!(wrapping_factorial(20), 2_192_834_560);i16::try_from(value).ok() to convert TryFrom results to Option.safe_i64_to_usize, remember that negative values and values larger than usize::MAX should both return None.checked_pow method works like checked_mul but for exponentiation.saturating_sum, use Iterator::fold with saturating_add.safe_average, first check if the slice is empty, then use checked arithmetic to compute the sum before dividing.wrapping_mul continues even when overflow occurs.