In a fixed-size numeric type (like u8
or usize
) we have a maximum and minimum value. At some point, further adds or subtracts will cause the representation to wrap around.
In debug mode, Rust programs will panic if a numeric wrapping occurs in an unexpected location. We can use wrapping_add
and wrapping_sub
(along with saturating versions) to help here.
Here we use the u8
type, which is just 1 byte
, to demonstrate the wrapping_add
and wrapping_sub
methods. We observe the effects of the methods.
wrapping_sub
on a u8
variable with the value 10. This subtracts 1, and gives us the value 9.fn main() { // Part 1: subtract 1 with wrapping sub. let mut value = 10u8; value = value.wrapping_sub(1); println!("{value}"); // Part 2: add 1 with wrapping add 20 times. let mut value = 250u8; for _ in 0..20 { value = value.wrapping_add(1); println!("{value}"); } }9 251 252 253 254 255 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
Instead of wrapping, we can specify the saturating behavior with saturating_add
and sub. This "maxes" out the values but does not allow them to wrap to 0.
saturating_add
on the starting value of 250 for a u8
. This goes to 255, and then stays there when we keep adding.fn main() { // Use saturating add on u8. let mut value = 250u8; for _ in 0..10 { value = value.saturating_add(1); println!("{value}"); } }251 252 253 254 255 255 255 255 255 255
For fixing panics in debug Rust programs, wrapping_add
and wrapping_sub
can be useful. This helps clarify the program's logic and eliminate unwanted behavior and bugs.