如何避免usize变负?

时间:2018-10-12 23:59:31

标签: indexing rust

我正在将一大块(2000行)专有C代码转换为Rust。在C语言中,通常向下运行一个指针,数组索引等,只要它为非负数即可。在Rust中,简化为骨头,看起来像:

while i >= 0 && more_conditions { 
    more_work;
    i -= 1;
}

当然,当iusize时,减法会导致下溢。我通过使用for的{​​{1}}循环,将索引偏移1或使用其他类型并使用.rev()进行强制转换来解决此问题。

通常它可以正常工作,通常我可以使它清晰易懂,但是我要修改的代码充满了相互接近的索引,并最终通过as usize

进行了测试

(在Rust中)

i_low > i_high

每次{@ {1}}超过0时,都会出现此恐慌。

我一直在代码中插入很多loop { while condition1(i_low) { i_low += 1; } while condition2(i_high) { j_high -= 1; } if i_low > i_high { return something; } do_something_else; } ,但是它变得不太可读。

经验丰富的Rust程序员如何避免i_high变量变为-1?

  1. 用于循环? j_high >= 0 &&

  2. 正在广播? usize,检查了for i in (0..size).rev()

  3. 将变量抵消1,并在安全时使用i as usize

  4. 附加条件吗?

  5. 捕获异常?

还是您最终会学会围绕这些情况编写程序?


说明:C代码没有中断-据称它已经投入生产十年,在24/7的多台服务器上构造视频片段。它只是不遵循Rust约定-它经常返回-1作为索引,它以-1递归以处理要处理的数组的低索引,并且索引始终为负。所有这些问题都在问题发生之前得到了处理-难看,但可以正常工作。像这样:

i < 0

在上面的代码中,三个结果调用中的每一个都可能得到一个-1的段索引(附加,存储)或超出范围(进程)的索引,但在调用之后才处理。

我的Rust代码似乎也可以正常工作。事实上,为了处理负数的usize,我添加了一些修剪许多递归的附加逻辑,因此它的运行速度与C代码一样快(显然更快,但这是因为我将输出分布在多个驱动器)

问题在于客户端不希望完全重写,而希望“本机”程序员能够相互检查这两个程序。根据目前为止的答案,我认为根据需要使用i64和强制转换/阴影可能是生成易于为“本地人”阅读的代码的最佳方法。我个人不必喜欢...

2 个答案:

答案 0 :(得分:5)

如果您想惯用:

for j in (0..=i).rev() {
    if conditions {
        break;
    }
    //use j as your new i here
}

请注意,此处在迭代器中使用了..=i,这意味着它实际上将包括i[0, 1, 2, ..., i-1, i]进行迭代,否则,您将得到[0, 1, 2, ..., i-2, i-1] < / p>

否则,这是代码:

while (i as isize - 1) != -2 && more_conditions { 
    more_work;
    i -= 1;
}

playground

答案 1 :(得分:1)

我可能首先使用saturating_sub(对于并行结构,则使用_add):

while condition1(i_low) { i_low = i_low.saturating_add(1); }
while condition2(i_high) { j_high = j_high.saturating_sub(1); }

您需要小心确保逻辑处理饱和为零的值。您还可以在wrapping_sub中使用更多类似C的语义。

说实在的,没有一种千篇一律的解决方案。很多时候,如果稍微抽象一下或将其稍微倾斜,复杂的逻辑就会变得更简单。您尚未提供任何具体示例,因此我们无法提供任何有用的建议。我用迭代器解决了太多问题,所以这通常是我的第一个解决方案。

  

捕获异常

绝对不是。那是极其低效且不习惯的。