我正在编写一个循环方法,用于向索引向前或向后移动索引。以下代码用于向后循环:
(i-1)%list_length
在这种情况下, i
属于那种类型 usize
,这意味着它是未签名的。如果 i
等于0,这导致'尝试减去溢出'错误。我尝试使用正确的转换方法来解决此问题:
((i as isize)-1)%(list_length as isize)) as usize
这导致整数溢出。
我理解错误发生的原因,目前我通过检查索引是否等于0来解决问题,但我想知道是否有某种方法可以通过将变量转换为正确的类型来解决它。
如 DK。指出,您不希望在整数级别包装语义:
fn main() {
let idx: usize = 0;
let len = 10;
let next_idx = idx.wrapping_sub(1) % len;
println!("{}", next_idx) // Prints 5!!!
}
相反,您希望使用模数逻辑来回绕:
let next_idx = (idx + len - 1) % len;
这只适用于 len
+ idx
小于该类型的最大值 - 这更容易看到一个 u8
代替 usize
;刚设置 idx
到200和 len
到250。
如果你不能保证两个值之和总是小于最大值,我可能会使用“已检查”系列操作。这与您已经提到的相同级别的条件检查有关,但整齐地绑在一行中:
let next_idx = idx.checked_sub(1).unwrap_or(len - 1);
如果您的代码可能有溢出操作,我建议使用 Wrapping
。允许时,您无需担心抛出或溢出恐慌:
use std::num::Wrapping;
let zero = Wrapping(0u32);
let one = Wrapping(1u32);
assert_eq!(std::u32::MAX, (zero - one).0);