简体   繁体   中英

trait with functions that return an iterator

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.

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> {
        /* ... */
    }
}

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() { }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM