Hello,
I would much appreciate your feedback on this simple function that takes a generic Iterator and returns both min and max in a single pass.
I have read that, when possible, calling .iter()
should be preferred to a direct for
loop or .into_iter()
because it borrows the elements to yield. And this is what I'm trying, am I correct? Is the distinction relevant in this case?
Then, the function signature that takes the obtained iterator (from calling .iter()
) should specify that the associated item type is a reference to a generic type, correct?
Finally, does the fact that I'm getting and iterator and passing it to the function cause some copy/clone of the data? i.e., the function doesn't take a reference to the iterator, but the iterator itself.
Am I correct in assuming that the only clone
will happen at the end of the function to return the owned min and max (rather than references)? I guess f64 may be copied during the min-max loop, but that is cheap and, thus, in line with Rust principles, correct?
How could I make it more idiomatic?
thank you very much in advance,
Luca
fn main() {
let v = [f64::NAN, f64::NAN, 1.1, f64::NAN, 2.5, 3.2, f64::NAN];
let iterv = v.iter().filter(|x| !x.is_nan());
let (min, max) = min_and_max(iterv);
assert_eq!(min, 1.1, "min {}", min);
assert_eq!(max, 3.2, "max {}", max);
assert_eq!(v[2], 1.1, "v[2] {}", v[2]);
let v = [String::from("c"), String::from("a"), String::from("b")];
let iterv = v.iter();
let (min, max) = min_and_max(iterv);
assert_eq!(min, String::from("a"), "min {}", min);
assert_eq!(max, String::from("c"), "max {}", max);
assert_eq!(v[2], String::from("b"), "v[2] {}", v[2]);
}
fn min_and_max<'a, I, T>(mut s: I) -> (T, T)
where
I: Iterator<Item=&'a T>,
T:
'a +
std::cmp::PartialOrd +
Clone,
{
let (mut min, mut max) = match s.next() {
Some(v) => (v, v),
None => panic!("could not get initial values"),
};
for es in s {
if es > max {
max = es
}
if es < min {
min = es
}
}
return (min.clone(), max.clone());
}