我正在将一大块(2000行)专有C代码转换为Rust。在C语言中,通常向下运行一个指针,数组索引等,只要它为非负数即可。在Rust中,简化为骨头,看起来像:
while i >= 0 && more_conditions {
more_work;
i -= 1;
}
当然,当i
为usize
时,减法会导致下溢。我通过使用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?
用于循环? j_high >= 0 &&
正在广播? usize
,检查了for i in (0..size).rev()
将变量抵消1,并在安全时使用i as usize
?
附加条件吗?
捕获异常?
还是您最终会学会围绕这些情况编写程序?
说明:C代码没有中断-据称它已经投入生产十年,在24/7的多台服务器上构造视频片段。它只是不遵循Rust约定-它经常返回-1作为索引,它以-1递归以处理要处理的数组的低索引,并且索引始终为负。所有这些问题都在问题发生之前得到了处理-难看,但可以正常工作。像这样:
i < 0
在上面的代码中,三个结果调用中的每一个都可能得到一个-1的段索引(附加,存储)或超出范围(进程)的索引,但在调用之后才处理。
我的Rust代码似乎也可以正常工作。事实上,为了处理负数的usize,我添加了一些修剪许多递归的附加逻辑,因此它的运行速度与C代码一样快(显然更快,但这是因为我将输出分布在多个驱动器)
问题在于客户端不希望完全重写,而希望“本机”程序员能够相互检查这两个程序。根据目前为止的答案,我认为根据需要使用i64和强制转换/阴影可能是生成易于为“本地人”阅读的代码的最佳方法。我个人不必喜欢...
答案 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;
}
答案 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的语义。
说实在的,没有一种千篇一律的解决方案。很多时候,如果稍微抽象一下或将其稍微倾斜,复杂的逻辑就会变得更简单。您尚未提供任何具体示例,因此我们无法提供任何有用的建议。我用迭代器解决了太多问题,所以这通常是我的第一个解决方案。
捕获异常
绝对不是。那是极其低效且不习惯的。