在列表中向后循环时,对“尝试通过溢出进行减法”感到恐慌

问题描述 投票:0回答:3

我正在为列表编写一个循环方法,该方法向前或向后移动索引。下面的代码用于向后循环:

(i-1)%list_length

在这种情况下,

i
的类型为
usize
,意味着它是无符号的。如果
i
等于 0,这会导致“尝试减去溢出”错误。我尝试使用正确的铸造方法来解决这个问题:

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

这会导致整数溢出。

我明白为什么会发生错误,目前我已经通过检查索引是否等于 0 解决了问题,但我想知道是否有某种方法可以通过将变量转换为正确的类型来解决它。

rust integer-overflow integer-arithmetic
3个回答
28
投票

作为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。

如果您不能保证两个值的总和始终小于最大值,我可能会使用“checked”操作系列。这会执行与您提到的相同级别的条件检查,但它整齐地绑定在一行中:

let next_idx = idx.checked_sub(1).unwrap_or(len - 1);

9
投票

如果你的代码可能有溢出操作,我建议使用

Wrapping
。当您允许时,您无需担心强制转换或溢出恐慌:

use std::num::Wrapping;

let zero = Wrapping(0u32);
let one = Wrapping(1u32);

assert_eq!(std::u32::MAX, (zero - one).0);

0
投票

有类似的问题,相当于

(i+list_length-1)%list_length

帮我解决了

© www.soinside.com 2019 - 2024. All rights reserved.