Returning iterator from a trait

I am trying to build shared functionality into a trait. I have this
functionality implemented for a Struct.

pub struct AtLeastTwo<T> {
    raw: Vec<T>
}

impl <T> AtLeastTwo<T> {
    pub fn new(a: T, b: T) -> AtLeastTwo<T> {
        AtLeastTwo::new_and(a, b, Vec::new())
    }

    pub fn new_and(a:T, b: T, mut v:Vec<T>) -> AtLeastTwo<T> {
        v.insert(0, a);
        v.insert(1, b);
        AtLeastTwo {
            raw: v
        }
    }

    fn as_slice(&self) -> &[T] {
        self.raw.as_slice()
    }

    fn iter(&self) -> impl Iterator<Item = &T> {
        self.as_slice().iter()
    }
}

Now I thought to move some of this functionality into a Trait.

trait AtCollection <T> {

    fn as_slice(&self) -> &[T];

    fn as_vec(self) -> Vec<T>;

    fn iter(&self) -> impl Iterator<Item = &T> {
        self.as_slice().iter()
    }
}

pub struct AtLeastTwo<T> {
    raw: Vec<T>
}

impl <T> AtLeastTwo<T> {
    pub fn new(a: T, b: T) -> AtLeastTwo<T> {
        AtLeastTwo::new_and(a, b, Vec::new())
    }

    pub fn new_and(a:T, b: T, mut v:Vec<T>) -> AtLeastTwo<T> {
        v.insert(0, a);
        v.insert(1, b);
        AtLeastTwo {
            raw: v
        }
    }

    fn as_slice(&self) -> &[T] {
        self.raw.as_slice()
    }

    fn iter(&self) -> impl Iterator<Item = &T> {
        self.as_slice().iter()
    }
}

impl <T> AtCollection<T> for AtLeastTwo<T> {
    fn as_slice(&self) -> &[T] {
        self.raw.as_slice()
    }

    fn as_vec(self) -> Vec<T> {
        self.raw
    }
}

However, this fails because I cannot use impl Iterator in the Trait
definition. The best I have come up with is too use Box as a
return type. Is this is the only way?

There's some info on why you can't do this (yet) in the RFC.

For now, your options depend on what you're intending to do with the trait:

  • If you intend to return different types of Iterator for different implementations of AtCollection, you'll need to either return a trait object (e.g. Box<dyn Iterator>) or somehow unify all of the possible return types into a single type (e.g. wrap them in an enum and then implement Iterator for that).
  • If you intend to return a single type of Iterator from the trait, you could just specify the full name of the type. In your case, it's std::slice::Iter.

Since you provide the implementation of iter, you should use std::slice::Iter.

If you are writing a trait and the implementors is supposed to implement iter, you should add a type Iter: Iterator to the trait and return Self::Iter. This way each implementer can choose which type of iterator they want. Of course, if they're using slices too, they'd have to do type Iter = std::slice::Iter in their impl block.

This is an excellent example of the latter method: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html

For examples of the first situation look at almost any provided method on the Iterator trait. For example map returns an std::iter::Map, which is a struct that implements Iterator, just like std::slice::Iter.

Thank you both. In this case, I wanted to type it as Iterator because intellectually it should be, but in practice the pinning the implementation down to std::slice::Iter is not a problem, so that seem a good way to go. Thank you for your help!

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.