当向量v可能为空时,循环超过0 .. v.len() - 1的正确方式是什么?

考虑下面的代码,它打印向量[5, 6, 7]中2个元素的所有 Select :

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![];

则程序由于溢出而死机,这也是预期的.

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

以下是一些我不想要的变通方法的示例:

  • 单独处理空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,而不是任何黑客.

推荐答案

请注意,如果为i == v.len()-1,则外层循环体中不会发生任何事情,因为i+1..v.len()是一个空迭代器.因此,避免整数下溢的最简单方法是简单地删除-1:

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

5 6
5 7
6 7

如果我将v替换为Vec::new(),您将不会得到任何输出,正如预期的那样.

Rust相关问答推荐

使用InlineTables序列化toml ArrayOfTables

为什么对不可复制数据的引用的取消引用没有O权限来避免Rust中的双重释放?

你是如何在铁 rust 一侧的金牛座获得应用程序版本的?

原始数组数据类型的默认trait实现

有没有一种惯用的方法来判断VEC中是否存在变体?

当对VEC;U8>;使用serde_json时,Base64编码是保护空间的好方法吗?

可以为rust构建脚本编写单元测试吗?

完全匹配包含大小写的整数范围(&Q;)

使用Rust WASM读取文件

Rust从关联函数启动线程

Rust:为什么 &str 不使用 Into

使用占位符获取用户输入

如何正确使用git2::Remote::push?

Rust 并行获取对 ndarray 的每个元素的可变引用

‘&T as *const T as *mut T’ 在 ‘static mut’ 项目中合适吗?

具有在宏扩展中指定的生命周期的枚举变体数据类型

如何在 Rust 中将 UTF-8 十六进制值转换为 char?

为什么 no_std crate 可以依赖于使用 std 的 crate?

为什么基于 clap::Parser 读取的大量数字进行计算比硬编码该数字时慢?

意外的正则表达式模式匹配