在列表中向后循环时在 'attempt to subtract with overflow' 处感到恐慌
Panicked at 'attempt to subtract with overflow' when cycling backwards though a list
我正在为一个向前或向后移动索引的列表编写一个循环方法。以下代码用于向后循环:
(i-1)%list_length
在这种情况下,i
是 usize
类型,这意味着它是无符号的。如果 i
等于 0,则会导致 'attempt to subtract with overflow' 错误。我尝试使用正确的转换方法来解决这个问题:
((i as isize)-1)%(list_length as isize)) as usize
这会导致整数溢出。
我明白为什么会出现错误,目前我已经通过检查索引是否等于 0 来解决问题,但我想知道是否有某种方法可以通过将变量转换为正确的类型。
如果你的代码可以有溢出操作,我建议使用Wrapping
。当您允许时,您无需担心强制转换或溢出恐慌:
use std::num::Wrapping;
let zero = Wrapping(0u32);
let one = Wrapping(1u32);
assert_eq!(std::u32::MAX, (zero - one).0);
作为 ,您不希望在整数级别包装语义:
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);
我正在为一个向前或向后移动索引的列表编写一个循环方法。以下代码用于向后循环:
(i-1)%list_length
在这种情况下,i
是 usize
类型,这意味着它是无符号的。如果 i
等于 0,则会导致 'attempt to subtract with overflow' 错误。我尝试使用正确的转换方法来解决这个问题:
((i as isize)-1)%(list_length as isize)) as usize
这会导致整数溢出。
我明白为什么会出现错误,目前我已经通过检查索引是否等于 0 来解决问题,但我想知道是否有某种方法可以通过将变量转换为正确的类型。
如果你的代码可以有溢出操作,我建议使用Wrapping
。当您允许时,您无需担心强制转换或溢出恐慌:
use std::num::Wrapping;
let zero = Wrapping(0u32);
let one = Wrapping(1u32);
assert_eq!(std::u32::MAX, (zero - one).0);
作为
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);