1

I have a struct that has an iterator over a borrowed slice, and I want to create a method that returns an iterator that does some computation on the contained iterator

Basically this:

#[derive(Clone)] struct Foo<'a> { inner: ::std::iter::Cycle<::std::slice::Iter<'a, u8>>, } impl<'a> Foo<'a> { pub fn new<T: AsRef<[u8]> + ?Sized>(vals: &'a T) -> Foo<'a> { Self { inner: vals.as_ref().iter().cycle(), } } pub fn iter(&mut self) -> impl Iterator<Item = u8> + 'a { self.inner.by_ref().map(Clone::clone) // simple case but this could be any computation } } 

Which yields a cryptic error.

Here's my understanding: I need to bind the returned iterator's lifetime to the &mut self of iter() so that &mut self is only dropped when .collect() is called on the returned iterator.

BUT, changing to fn iter(&'a mut self) isn't good enough because &'a mut self now lives for the entire duration of the struct instance (meaning that calling collect() doesn't drop that reference). Which prevents something like this

#[test] fn test(){ let mut foo = Foo::new("hello, there"); foo.iter().zip(0..4).collect::<Vec<_>>(); // call once, ok foo.iter().zip(0..4).collect::<Vec<_>>(); // error because 2 &mut references exist at the same } 

rust playground link

1
  • If, instead of defining the type of inner in the struct definition such that the struct gets parameterised by 'a, you could just make the type of inner generic. Commented Jul 22, 2021 at 22:46

1 Answer 1

1

The way I would do this is to make a struct just for iterating over those items. It makes things much easier.

 ... pub fn iter(&mut self) -> ClonedFooIter<'a, '_> { ClonedFooIter { inner: &mut self.inner, } } } pub struct ClonedFooIter<'a, 'b> { inner: &'b mut std::iter::Cycle<::std::slice::Iter<'a, u8>>, } impl<'a, 'b> Iterator for ClonedFooIter<'a, 'b> { type Item = u8; fn next(&mut self) -> Option<Self::Item> { self.inner.next().cloned() } } 

The idea is that the returned struct only lives till the mutable borrow of self lives.

Using a struct makes naming the iterator type easier too.

Sign up to request clarification or add additional context in comments.

1 Comment

Hi, thanks for the answer, unfortunately cloning doesn't quite work for my use-case, as I need inner to be stateful

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.