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?

1 Like

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.
1 Like

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.

2 Likes

This is an excellent example of the latter method: IntoIterator in std::iter - Rust

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.