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

String 带范围的算术运算顺序问题,string,rust,range,String,Rust,Range,我正试图通过铁锈书和Exercism.io网站学习铁锈。 我对你有意见。代码如下: pub fn series(_digits: &str, _len: usize) -> Vec<String> { (0.._digits.len() + 1 - _len) .map(|i| _digits[i..i + _len].to_string()) .collect() } 我很惊讶,因为它看起来对我来说是一样的。为什么会失败?发生

我正试图通过铁锈书和Exercism.io网站学习铁锈。 我对你有意见。代码如下:

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

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

发生这种情况是因为在调试模式下,会溢出的算术运算会死机,而死机会导致测试失败

对于重新排列的版本(),在
系列(“12345”,6)
中,
数字.len()-len+1
变为
5usize-6usize+1usize
。程序甚至不能到达
+1
,因为
5usize-6usize
会恐慌。(
usize
不能表示负数,因此从
5
中减去
6
会导致溢出。)

错误消息包含故障性质的强烈提示:

——测试太长标准输出----
线程“test_too_long”在“尝试使用溢出进行减法”时惊慌失措,src/lib.rs:2:9
注意:使用'RUST_BACKTRACE=1'运行回溯跟踪。
然而,
digits.len()+1-len
可以工作,因为
6
正好比字符串长度多一个,因此
5+1-6
可以计算为零而不会溢出。但是如果您更改
test\u太长
而调用
series(“12345”,7)
,两个版本都会死机。这似乎是编写测试套件的人的疏忽,特别是考虑到指令没有指定预期的行为:

如果你要求从一个5位数的字符串中得到一个6位数的序列,你应该得到你所得到的一切


值得一提的是,这里有一种方法可以使
系列
为大于输入长度的任何
len
返回一个空向量:
(digits.len()+1)。饱和_sub(len)
类似于
digits.len()+1-len
,但如果减法的结果小于
0
,它只返回
0

检查错误消息。它说的不仅仅是测试失败。你是对的,我没有检查,这帮助我理解了这个问题。这是“尝试使用溢出进行减法”x)不要在变量名前面加下划线(
uuu
)。这表示该变量未使用,但对您的两个变量都不适用。请注意,如果您使用
&[u8]
而不是字符串类型,代码将变得容易得多。您的
系列
函数将变成
digits.windows(len.collect()
#[test]
#[ignore]
fn test_too_long() {
    let expected: Vec<String> = vec![];
    assert_eq!(series("92017", 6), expected);
}