Panic when trying to subtract with overflow when cycling backward through the list

I am writing a loop method for a list that moves the index forward or backward. The following code is used to loop backward:

(i-1)%list_length 

In this case, i is of type usize , that is, it has no sign. If i is 0, this results in an "attempt to subtract with overflow" error. I tried using the right casting methods to get around this problem:

 ((i as isize)-1)%(list_length as isize)) as usize 

This leads to overflow of integers.

I understand why errors occur, and at the moment I solved the problem by checking if the index is 0, but I was wondering if there was any way to solve it by translating the variables into the correct types.

+8
integer-overflow rust integer-arithmetic
source share
2 answers

Like DK. indicates , you do not want to wrap semantics at the integer level:

 fn main() { let idx: usize = 0; let len = 10; let next_idx = idx.wrapping_sub(1) % len; println!("{}", next_idx) // Prints 5!!! } 

Instead, you want to use modular logic for rounding:

 let next_idx = (idx + len - 1) % len; 

This only works if len + idx less than max. type - it is much easier to see using u8 instead of usize ; just set idx to 200 and len to 250.

If you cannot guarantee that the sum of the two values ​​will always be less than the maximum value, I would probably use a β€œverified” family of operations. This does the same level of conditional checking that you talked about that you already have, but are neatly tied to a single line:

 let next_idx = idx.checked_sub(1).unwrap_or(len - 1); 
+4
source share

If your code can have crowded operations, I would suggest using Wrapping . You do not need to worry about casting or panic overflows when you allow:

 use std::num::Wrapping; let zero = Wrapping(0u32); let one = Wrapping(1u32); assert_eq!(std::u32::MAX, (zero - one).0); 
+3
source share

All Articles