当 v 可能为空时如何循环 0 .. v.len() - 1?

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

当向量

0 .. v.len() - 1
可能为空时,循环
v
的正确方法是什么?

考虑以下代码,它打印向量中 2 个元素的所有选择

[5, 6, 7]

fn main() {
  let v: Vec<i32> = vec![5, 6, 7];
  for i in 0 .. v.len() - 1 {
    for j in i + 1 .. v.len() {
      println!("{} {}", v[i], v[j]);
    }
  }
}

打印出来了

5 6
5 7
6 7

正如预期的那样。

现在,如果我们有

let v: Vec<i32> = vec![];

然后程序会因为溢出而恐慌,这也在意料之中。

:如何在不改变程序结构和逻辑、不涉及有符号整数的情况下修复它?

以下是我不想要的解决方法的一些示例:

  • 单独处理空
    v
    (改变逻辑)。总的来说,我不想检查
    v
    是否为空,例如通过
    if v.len() == 0 { 0 } else { v.len() - 1 }
  • 更改循环顺序(更改逻辑和输出):
for j in 0 .. v.len() {
    for i in 0 .. j {
  • 移动索引(改变逻辑):
for i in 1 .. v.len() {
    for j in i .. v.len() {
        // Now i is shifted by 1
  • 使用 i32(强制转换):
for i in 0 .. v.len() as i32 - 1 {
    for j in i + 1 .. v.len() as i32 {
        // cast i and j to usize

总的来说,我希望有一种干净的方法来处理

0 .. v.len() - 1
,而不需要任何黑客攻击。

rust integer-overflow unsigned-integer
2个回答
1
投票

为了解决当向量

0 .. v.len() - 1
可能为空时处理
v
的问题,我们可以使用 Rust 的
checked_sub
方法从向量的长度中安全地减一,而不会有整数下溢的风险。如果减法会导致下溢,则此方法返回
Option
,即
None
,否则返回结果
Some

以下是如何在代码中实现它:

fn main() {
    let v: Vec<i32> = vec![5, 6, 7];
    if let Some(max_index) = v.len().checked_sub(1) {
        for i in 0..max_index {
            for j in i + 1..v.len() {
                println!("{} {}", v[i], v[j]);
            }
        }
    }
    // If v is empty, the loop will not execute, avoiding the panic.
}

即使向量

v
为空,此代码也能正常工作,因为
checked_sub(1)
将返回
None
并且循环不会执行。该方案不会改变程序的结构或逻辑,不涉及有符号整数,也不需要单独处理空向量情况。


0
投票

经过更多谷歌搜索后,我发现 saturating_sub “在数字边界处饱和而不是溢出”。因此,

0usize.saturating_sub(1usize)
将是
0usize
,从而根据需要产生范围
0usize .. 0usize

fn main() {
  let v: Vec<i32> = vec![];
  for i in 0 .. v.len().saturating_sub(1) {
    for j in i + 1 .. v.len() {
      println!("{} {}", v[i], v[j]);
    }
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.