Instead of calling collect
the first time, just advance the iterator:
let mut values = string_value
.splitn(2, "-")
.map(|part| part.parse().unwrap());
let start = values.next().unwrap();
let end = values.next().unwrap();
Do not call .ok().unwrap()
— that converts the Result
with useful error information to an Option
, which has no information. Just call unwrap
directly on the Result
.
As already mentioned, if you want to return a Vec
, you'll want to call collect
to create it. If you want to return an iterator, you can. It's not bad even in stable Rust:
fn parse_range(string_value: &str) -> std::ops::Range<u8> {
let mut values = string_value
.splitn(2, "-")
.map(|part| part.parse().unwrap());
let start = values.next().unwrap();
let end = values.next().unwrap();
start..end + 1
}
fn main() {
assert!(parse_range("1-5").eq(1..6));
}
Sadly, inclusive ranges are not yet stable, so you'll need to continue to use +1
or switch to nightly.
Since splitn(2, "-")
returns exactly two results for any valid string_value
, it would be better to assign the tuple directly to two variables first and last rather than a seemingly arbitrary-length Vec
. I can't seem to do this with a tuple.
This is not possible with Rust's type system. You are asking for dependent types, a way for runtime values to interact with the type system. You'd want splitn
to return a (&str, &str)
for a value of 2
and a (&str
, &str
, &str
) for a value of 3
. That gets even more complicated when the argument is a variable, especially when it's set at run time.
The closest workaround would be to have a runtime check that there are no more values:
assert!(values.next().is_none());
Such a check doesn't feel valuable to me.
See also: