EDIT: see below for a summary of my understanding trying to put all the great replies in a single place
Here's the reduced code showing what I'm trying to understand:
struct RefHolder<'a> {
data_mut: &'a mut [u8],
data_shared: &'a [u8],
}
impl<'a> RefHolder<'a> {
//1) yield a shared reference to a subslice with the lifetime of the holding struct
fn yield_wide<'fun>(&'fun mut self, pos: usize) -> &'a [u8] {
&self.data_shared[pos..]
}
//2) yield a shared reference to a subslice with the (narrower) lifetime of the function scope
fn yield_narrow<'fun>(&'fun mut self, pos: usize) -> &'fun [u8] {
&self.data_shared[pos..]
}
// 3) yield an exclusive reference to a subslice with the lifetime of the holding struct
// NOTE: need to constrain 'fun: 'a as per compiler suggestion
fn yield_mut_wide<'fun: 'a>(&'fun mut self, pos: usize) -> &'a mut [u8] {
&mut self.data[pos..]
}
//4) yield an exclusive reference to a subslice with the (narrower) lifetime of the function scope
fn yield_mut_narrow<'fun>(&'fun mut self, pos: usize) -> &'fun mut [u8] {
&mut self.data[pos..]
}
}
I got into this while trying to better understand what GATs bring to the table, which drove me down the rabbit hole of trying to implement a mutable iterator which finally got me to a case similar to the one shown above.
Here are my questions:
-
First I'd like to check if the following reasoning is correct for why I need to put the
'fun: 'a
bound in case 3: my understanding is that the signature of the function is promising to return something tied to the lifetime of the RefHolder instance, but sincenon-'static
returned references must originate from (reference) function arguments, in this case the returned value will be tied to the lifetime of&mut self
which the compiler has to pessimistically assume being shorter than'a
and hence it asks for a guarantee that'fun
is at least as long as'a
-
Regardless, why the same bound is not required for the corresponding (but non-mutable) case number 1? Is the compiler performing some kind of implicit lifetime augmentation because of non-mutability? Has it anything to do with variance/subtyping kicking in for the non-mutable case? I'm quite confused here...
Thanks,
Andrea