A struct has a set of items I'd like to allow clients to iterate over. Here's an attempt:
use std::collections::HashSet;
use std::hash::Hash;
pub struct Foo<T: Eq + Hash> {
items: HashSet<T>,
}
impl<'a, T: 'a + Eq + Hash> Foo<T> {
pub fn new() -> Self {
Foo {
items: HashSet::new(),
}
}
pub fn iterate<I>(&self) -> I
where
I: IntoIterator<Item = &'a T>,
{
self.items.iter()
}
}
This fails to compile, giving the error:
error[E0308]: mismatched types
--> src/lib.rs:19:9
|
15 | pub fn iterate<I>(&self) -> I
| - expected `I` because of return type
...
19 | self.items.iter()
| ^^^^^^^^^^^^^^^^^ expected type parameter, found struct `std::collections::hash_set::Iter`
|
= note: expected type `I`
found type `std::collections::hash_set::Iter<'_, T>`
= help: type parameters must be constrained to match other types
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
The return value from HashSet::iter
method appears to act like an Iterator
when, for example within a for loop. It seems like some kind of type coercion might be possible in my iterate
method, but clearly the compiler has other ideas.
How can I specify a return type of Iterator
in a function while returning the return value from a HashSet
iterator?
In other words, I want to delegate iteration to HashSet
. I'd like to avoid implementing a custom iterator to do this, but if that's the only way would be interested in seeing how it's done. I've been able to get this working by returning a Box<dyn Iterator>
, but I'd like to avoid that approach as well if it's possible to work just with trait boundaries as described in this answer.
One more requirement: the approach must work when the iterate
method is declared on a trait. That appears to rule out an approach like:
pub trait FooTrait {
fn iterate(&self) -> impl Iterator<Item=&T>;
}