Difference life time extension of & and &mut

Hello,

I do not understand why Ref::f compiles but RefMut::f does not:

struct Ref<'a>{
    val: &'a f64
}
impl<'a> Ref<'a> {
    fn f(&self) -> &'a f64 {
        self.val
    }
}

struct RefMut<'a>{
    val: &'a mut f64
}
impl<'a> RefMut<'a> {
    fn f(&self) -> &'a f64 {
        self.val //COMPILER ERROR: lifetime may not live long enough
    }
}

Some one could explain me please?

For Ref, & references implement Copy, so the function is able to just return a copy of the reference stored in the struct. For RefMut, &mut references can't implement Copy, since they need to be unique. That means the only way the &mut reference can be returned is either by moving it out (which requires that you either replace it with another reference or that you have ownership of the struct and destroy it, neither of which work well here) or reborrowing through the self reference (which has the lifetime parameter of that reference rather than 'a, yielding the error you get since the lifetimes don't match).

8 Likes

And to explain why the compiler error is correct: if your code could compile, you could call f and get a &'a f64 that remains valid after the &self reference expired and made the val: &'a mut f64 usable/"active" again. That is, you have an active &'a mut _ and &'a _ which alias each other, which is undefined behavior.

Example.

3 Likes

I understand better the borrow rules thanks to you, tx.

    struct RefMut<'a> {
        val: &'a mut f64,
    }
    impl<'a> RefMut<'a> {
        fn f<'s: 'a>(&'s self) -> &'a f64 {
            self.val  //COMPILES
        }
    }

1 Like