1

I have the following structure:

trait DoesIt: Sized {
    fn do_it(self) -> usize {
        // Only adding default impl for this example,
        // normally these are different for the One and Two below;
        3
    }
}

struct One {}

struct Two {}

impl DoesIt for One {}
impl DoesIt for Two {}

enum Container {
    Ones(Vec<One>),
    Twos(Vec<Two>),
}

trait HasContainer {
    fn get(self) -> Container;
}

struct Outer {
    container: Container,
}

impl HasContainer for Outer {
    fn get(self) -> Container {
        self.container
    }
}

I would like to have a trait Works, which, if implemented, would allow iterating over things that implement DoesIt - in this case Ones or Twoes (whichever the Container enum holds).

Attempts

  1. I've tried implementing IntoIter for the Outer, but due to rustc --explain E0207 this does not work, since I cannot bind the IntoIter<Item = T> to some trait.

  2. Creating a wrapping generic struct which also holds a PhantomData to capture the type, and them implement IntoIter for that. This also does not work since it does not return the Item type (which is generic), but rather the particular One or Two. As of the following does not work, but I'd like it to:

    struct PhantomContainer<T: DoesIt, S> {
        a_type: PhantomData<S>,
        pub it: T,
    }
    
    impl<T, I> for PhancomContainer<T, I>
    where
        I: DoesIt,
        T: HasContainer,
    {
        type Item = I;
        type IntoIterator = std::vec::IntoIter<Self::Item>;
    
        fn into_iter(self) -> Self::IntoIter {
            match self.it.get() {
                Container::Ones(ones) => (ones as Vec<I>).into_iter(),
                Container::Twos(twoes) => (twoes as Vec<I>).into_iter(),
            }
        }
    }
    
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Your second code block isn't valid Rust syntax. – Shepmaster Oct 14 '20 at 18:49
  • *I would like to have a trait `Works`* — it's not clear where that trait is supposed to come into play as it's not demonstrated anywhere. – Shepmaster Oct 14 '20 at 18:50
  • `PhantomContainer` ≠ `PhancomContainer`. Please test your code locally before posting it. – Shepmaster Oct 14 '20 at 18:50
  • Your question might be answered by the answers of [How do I create a heterogeneous collection of objects?](https://stackoverflow.com/q/27957103/155423). If not, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Oct 14 '20 at 18:52
  • TL;DR the duplicate: return *trait objects* or another enum from your iterator. – Shepmaster Oct 14 '20 at 18:52
  • 1
    Note that return an enum is what you want as a Rust beginner, and return a trait object is not what a non beginner will do either. it's just very hard to handle it, return an enum is what you want in 95% of case. – Stargateur Oct 14 '20 at 19:39
  • @Shepmaster thanks, the heterogeneous collections seem to be related. In light of that, then the core of my question can be rephrased: Given an enum of heterogeneous collections (where all elements implement the same one trait), how would one implement an iterator that yields those trait objects from the enum? (I'll give this a go myself in ~12h. I _think_ I know how to do it, but not 100% certain) – T. Ostasevicius Oct 14 '20 at 20:08
  • Interesting question. And although I hate when people say this, and Im saying it you now, why would you want to iterate over contents of `Vec` in a variant of enum when you can directly match on enum and iterate??!! One way is to drain elements from source vec and create a new vec from it. Like here https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b45002980a7f78e2695deaa8dad4a9bd – Boss Man Oct 14 '20 at 21:32

0 Answers0