RBF06
RBF06

Reputation: 2419

Create Iterator that yields references to its fields

I would like to define a struct that implements Iterator such that the items yielded are references to one of the the struct's fields.

Lets say I have defined my struct like this:

struct InnerType;
struct MyStruct {
    field: InnerType
}

The following does not work because the Associated Type Item requires an explicit lifetime parameter:

impl Iterator for MyStruct {
    type Item = &InnerType;
    fn next(&mut self) -> Option<Self::Item> { Some(&self.field) }
}

Adding a lifetime parameter there doesn't work either because "the lifetime parameter 'a is not constrained by the impl trait, self type, or predicates".

impl<'a> Iterator for MyStruct {
    type Item = &'a InnerType;
    fn next(&mut self) -> Option<Self::Item> { Some(&self.field) }
}

Not sure what I'm missing. What is going on here? Is there some reason(s) not to have an iterator which yields items borrowing from itself?

Upvotes: 1

Views: 323

Answers (1)

cadolphs
cadolphs

Reputation: 9647

Is this really what you want? Or would you rather want it so that someone can request an iterator over MyStruct, the way someone would call iter() on a Vec?

If that's the case, you're lucky. You just need a different struct actually implementing the Iterator trait and that struct will contain a reference to field.

struct InnerType;
struct MyStruct {
    field: InnerType
}

struct MyIterator<'a> {
    field: &'a InnerType
}

impl MyStruct {
    fn iter<'a>(&'a self) -> MyIterator<'a> {
        MyIterator{ field: &self.field }
    }
}

impl<'a> Iterator for MyIterator<'a> {
    type Item = &'a InnerType;
    fn next(&mut self) -> Option<Self::Item> { Some(self.field) }
}

fn main() {
    let foo: InnerType = InnerType{};
    
    let my_struct = MyStruct{ field: foo };
    
    let mut it = my_struct.iter();
    
    let item = it.next();
    
    assert!(item.is_some());
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=795bc0433a3a4e621486ecddf8f0a787

Otherwise, there's some discussions on here already about the issue with "streaming iterators", that is, iterators that return references to items in self.

See, for example, here: Iterator lifetime issue when returning references to inner collection

Now this mentions that Generic Associated Types would be required. And those have now made their way into stable Rust (1.65) but I'm not sure if that means that the standard Iterator trait now supports that type of streaming iterator.

Upvotes: 3

Related Questions