Reputation: 21
I'm trying to learn Rust using the Rust book and the Exercism.io website. I have an issue with this specific exercise. The code is as follows:
pub fn series(_digits: &str, _len: usize) -> Vec<String> {
(0.._digits.len() + 1 - _len)
.map(|i| _digits[i..i + _len].to_string())
.collect()
}
For example, series("12345", 3)
should return a Vec
containing ["123", "234", "345"]
.
Instead of (0.._digits.len() + 1 - _len)
, I experimented using (0.._digits.len() - _len + 1)
instead, but in this case, the unit test "test_too_long" fails:
#[test]
#[ignore]
fn test_too_long() {
let expected: Vec<String> = vec![];
assert_eq!(series("92017", 6), expected);
}
I'm surprised because it looks like it's the same to me. Why did it fail?
Upvotes: 0
Views: 138
Reputation: 27945
This happens because in debug mode, arithmetic operations that would overflow instead panic, and panicking causes tests to fail.
With the rearranged version (playground), in series("12345", 6)
, digits.len() - len + 1
becomes 5usize - 6usize + 1usize
. The program doesn't even get to the + 1
, because just 5usize - 6usize
panics. (usize
can't represent negative numbers, so subtracting 6
from 5
causes overflow.)
The error message contains a strong hint at the nature of the failure:
---- 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
works, however, because 6
is exactly one more than the length of the string, and so 5 + 1 - 6
can evaluate to zero without overflow. But if you change test_too_long
to call series("12345", 7)
instead, both versions panic. This seems like an oversight on the part of whoever wrote the test suite, especially considering that the instructions don't specify the expected behavior:
And if you ask for a 6-digit series from a 5-digit string, you deserve whatever you get.
For what it's worth, here's one way to make series
return an empty vector for any len
greater than the length of the input: (digits.len() + 1).saturating_sub(len)
is like digits.len() + 1 - len
, but if the result of the subtraction would be less than 0
, it just returns 0
.
Upvotes: 1