Borrow and internal IntoIterator

48 views Asked by At

I though I got smart with lifetimes, but the compiler teaches me again...

error[E0521]: borrowed data escapes outside of method

play


pub struct Bugger<S> {
    pub items: S,
}
impl<S> Bugger<S>
where
    &'static S: IntoIterator + 'static,
    <&'static S as IntoIterator>::Item: AsRef<u8>,
{
    fn do_something_with_items(&self) -> impl  Iterator<Item = u8> {
        (&self.items).into_iter().map(|b| *b.as_ref())
    }
}

I want to accept a generic member that implements the IntoIterator on it's reference and then use it in another method, actually a trait impl, but even this fails.

1

There are 1 answers

1
cdhowie On BEST ANSWER

The primary reason this fails to compile is because you take &self (which must be valid for any lifetime) but the bound on the implementation block requires IntoIterator to be implemented for a reference with 'static lifetime. The way you use this bound in the method therefore requires that the &self reference also be 'static, but you've not indicated this. You can fix this specific example by having the method take &'static self.

However, this is likely not what you want anyway. Most likely, you want a lifetime shorter than 'static. You can describe this in the trait bound with a higher-rank trait bound (HRTB).

You also need to indicate in the return type that the returned iterator borrows from self, which you can do by adding the anonymous lifetime '_ to the bound.

pub struct Bugger<S> {
    pub items: S,
}

impl<S> Bugger<S>
where
    for<'a> &'a S: IntoIterator,
    for<'a> <&'a S as IntoIterator>::Item: AsRef<u8>,
{
    fn do_something_with_items(&self) -> impl Iterator<Item = u8> + '_ {
        (&self.items).into_iter().map(|b| *b.as_ref())
    }
}

(Playground)

Note that the anonymous lifetime is just syntactic sugar for this:

fn do_something_with_items<'a>(&'a self) -> impl Iterator<Item = u8> + 'a