I\'d like to write a function that accepts an iterator and returns the results of some operations on it. Specifically, I\'m trying to iterate over the values of a Has
Easiest is using an impl Trait, impl Iterator:
use std::collections::HashMap;
fn find_min<'a>(vals: impl Iterator<Item = &'a u32>) -> Option<&'a u32> {
vals.min()
}
fn main() {
let mut map = HashMap::new();
map.insert("zero", 0u32);
map.insert("one", 1u32);
println!("Min value {:?}", find_min(map.values()));
}
playground
You want to use generics here:
fn find_min<'a, I>(vals: I) -> Option<&'a u32>
where
I: Iterator<Item = &'a u32>,
{
vals.min()
}
Traits can be used in two ways: as bounds on type parameters and as trait objects. The book The Rust Programming Language has a chapter on traits and a chapter on trait objects that explain these two use cases.
Additionally, you often want to take something that implements IntoIterator as this can make the code calling your function nicer:
fn find_min<'a, I>(vals: I) -> Option<&'a u32>
where
I: IntoIterator<Item = &'a u32>,
{
vals.into_iter().min()
}
This behaviour is a little unintuitive from those with a Python background rather than, say, a C++ background, so let me clarify a little.
In Rust, values are conceptually stored inside the name that binds them. Thus, if you write
let mut x = Foo { t: 10 };
let mut y = x;
x.t = 999;
y.t will still be 10.
So when you write
let x: Iterator<Item=&'a u32>;
(or the same in the function parameter list), Rust needs to allocate enough space for any value of type Iterator<Item=&'a u32>. Even if this was possible, it wouldn't be efficient.
So what Rust does instead is offer you the option to
Put the value on the heap, eg. with Box, which gives Python-style semantics. Then you can take generically with &mut Iterator<Item=&'a u32>.
Specialize each function invocation for each possible type to satisfy the bound. This is more flexible, since a trait reference is a possible specialization, and gives the compiler more opportunities for specialization, but means you can't have dynamic dispatch (where the type can vary dependent on runtime parameters).