Incombatible lifetimes for Iterator implementations when owning a "generator object"

Hi everyone,

I have a problem with lifetimes and iterators. Given a data-structure like

    pub struct Generator;

    impl Generator {
        fn items<'a>(&'a self) -> Box<Iterator<Item=u32> + 'a> {
            Box::new(0u32..10u32)
        }
    }

    pub struct ContainerOwned<'a> {
        it: Option<Box<Iterator<Item=u32> + 'a>>,
        gen: Generator,
    }

I would like it to implement Iterator in a way that the it field is updated in the next(...) function by calling a function on gen:

    impl<'a> Iterator for ContainerOwned<'a> {
        type Item=u32;
        
        fn next(&mut self) -> Option<u32> {
            if self.it.is_none() {
                // Compiler error here:
                self.it = Some(self.gen.items());
            }
            
            if let Some(ref mut it) = self.it {
                return it.next();
            }
            None
        }
    }

This will not compile with a "conflicting requirements" error message (full playground example: Rust Playground)

However, if I use a reference as field like in

    pub struct ContainerReference<'a> {
        it: Option<Box<Iterator<Item=u32> + 'a>>,
        gen: &'a Generator,
    }

it works fine (full playground example Rust Playground)

Currently I'm stucked in trying to understand why the reference works but not the owned one not. Do you have any ideas?

The case that doesn't work boils down to a self-referential struct - this comes up from time to time in Rust. In short (google/search for more details), a struct cannot have references to itself; self.it = Some(self.gen.items()) would create that situation because gen is owned by ContainerOwned and items() returns an iterator that in turn yields references with a lifetime tied to gen.

If you did (note the 'static lifetime of the iterator):

impl Generator {
    fn items<'a>(&'a self) -> Box<Iterator<Item=u32> + 'static> {
        Box::new(0u32..10u32)
    }
}

then it would work.

1 Like

Thank you for you response! I did have some issues with self-references in other parts of my code which I could resolve, but I totally missed that this is same problem here.