Reputation: 5162
I'm trying to build a trait with functions that return an iterator.
My simple example looks like this:
pub trait TraitA {
fn things(&self) -> Iterator<Item=&u8>;
}
fn foo<A: TraitA>(a: &A) {
for x in a.things() { }
}
Which does not work because the Iterator size type is not known at compile time.
Upvotes: 22
Views: 4407
Reputation: 13792
Rust's libstd has one implementation of this, the trait IntoIterator
.
/// Conversion into an `Iterator`
pub trait IntoIterator {
/// The type of the elements being iterated
type Item;
/// A container for iterating over elements of type `Item`
type IntoIter: Iterator<Item=Self::Item>;
/// Consumes `Self` and returns an iterator over it
fn into_iter(self) -> Self::IntoIter;
}
The trait has this peculiar by-value (self
) formulation exactly to be able to express both “into iterator” and “borrow iterator” semantics.
Demonstrated by HashMap's IntoIterator
implementations. (They use the hashmap's iterator structs Iter
and IntoIter
.) What's interesting here is that the trait is implemented for the type &HashMap<K, V, S>
to express the “borrow iterator”.
impl<'a, K, V, S> IntoIterator for &'a HashMap<K, V, S>
where K: Eq + Hash, S: HashState
{
type Item = (&'a K, &'a V);
type IntoIter = Iter<'a, K, V>;
fn into_iter(self) -> Iter<'a, K, V> {
self.iter()
}
}
impl<K, V, S> IntoIterator for HashMap<K, V, S>
where K: Eq + Hash, S: HashState
{
type Item = (K, V);
type IntoIter = IntoIter<K, V>;
/// Creates a consuming iterator, that is, one that moves each key-value
/// pair out of the map in arbitrary order. The map cannot be used after
/// calling this.
fn into_iter(self) -> IntoIter<K, V> {
/* ... */
}
}
Upvotes: 12
Reputation: 5162
Based on another question, I thought that the best way to do it would be to define the Iterator as a trait type, like so:
pub trait TraitA<'a> {
type I1: Iterator<Item=u8>;
type I2: Iterator<Item=&'a u8>;
fn iter_i1(&self) -> Self::I1;
fn iter_i2(&self) -> Self::I2;
}
fn foo<'a, A: TraitA<'a>>(a: &A) {
for x in a.iter_i1() { }
for x in a.iter_i2() { }
}
Upvotes: 4