带范围的算术运算顺序问题

时间:2019-01-01 23:10:38

标签: string rust range

我正在尝试使用Rust书和Exercism.io网站学习Rust。 我对this specific exercise有疑问。代码如下:

pub fn series(_digits: &str, _len: usize) -> Vec<String> {
    (0.._digits.len() + 1 - _len)
        .map(|i| _digits[i..i + _len].to_string())
        .collect()
}

例如,series("12345", 3)应该返回包含Vec的{​​{1}}。

我使用["123", "234", "345"]代替了(0.._digits.len() + 1 - _len),但是在这种情况下,单元测试“ test_too_long”失败了:

(0.._digits.len() - _len + 1)

我很惊讶,因为看起来对我来说是一样的。为什么失败了?

1 个答案:

答案 0 :(得分:1)

之所以会发生这种情况,是因为在调试模式下,本来会因恐慌而溢出的算术运算和恐慌导致测试失败。

使用重新排列的版本(playground),在series("12345", 6)中,digits.len() - len + 1变成5usize - 6usize + 1usize。该程序甚至没有进入+ 1,因为只有5usize - 6usize恐慌。 (usize不能代表负数,因此从6中减去5会导致溢出。)

错误消息强烈暗示了故障的性质:

---- test_too_long stdout ----
thread 'test_too_long' panicked at 'attempt to subtract with overflow', src/lib.rs:2:9
note: Run with `RUST_BACKTRACE=1` for a backtrace.

digits.len() + 1 - len可以工作,因为6比字符串的长度精确 一倍,因此5 + 1 - 6可以求值为零而不会溢出。但是,如果您将test_too_long改为调用series("12345", 7),则两个版本都会出现故障。这似乎是编写测试套件的任何人的疏忽,尤其是考虑到说明未指定预期行为的情况:

  

如果您要求从5位数字的字符串中获取6位数字的序列,那么您应得到的一切都应该得到。

对于它的价值,这是一种使series返回大于输入长度的len的空向量的一种方法:(digits.len() + 1).saturating_sub(len)就像digits.len() + 1 - len,但是如果相减的结果小于0,它只会返回0