Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do lifetimes interact with (re)borrowing and dereferencing?

Tags:

rust

Having a C/C++ background, I am trying to understand how lifetimes, struct field access,dereferencing and referencing play together. Unfortunately I cannot find a thorough explanation in the Book nor in similar posts. Please consider the following code that compiles:

struct NotCopyable {}

struct B<'a> {
    b: &'a NotCopyable,             // Copy-able
    c: &'a mut NotCopyable,         // Not Copy-able
    d: Option<&'a mut NotCopyable>, // Not Copy-able
}

impl<'a> B<'a> {
    fn some_f<'s>(&'s mut self) {
        // 1.
        let _b: &'a NotCopyable = &(*(self.b));

        // 2. COMPILER REJECTS as 'lifetime may not live long enough'
        // let _c: &'a mut NotCopyable = &mut (*(self.c));

        // 3.
        let _c: &'s mut NotCopyable = &mut (*(self.c));

        // 4.
        let _d: &'a mut NotCopyable = &mut *(self.d.take().unwrap());
    }
}

Assignments 1 and 4 show that the lifetime of both & () and &mut () outputs depends on the input lifetime, at least when reborrowing does not come into play. Wrong assignment 2 shows that the right-end side has lifetime 's and cannot be bound to 'a. Ok.

The lifetime mechanics in the the right-hand side of assignment 3 are unclear to me. I only concluded that the following steps somehow happen (please forgive me for the notation/terminology, but I hope the meaning is clear):

self.c: &'a mut NotCopyable -> *() -> _: 's mut NotCopyable -> &mut () -> _: &'s mut NotCopyable

that is, two noticeable things occur between the input and the output of the operator *() :

  • The lifetime of the mutable reference in the place addressed by self.c, namely 'a, is replaced with self lifetime, 's.
  • the lifetime 's sticks to the output temporary object, which I improperly annotated with 's mut NotCopyable.

I have read about reborrowing, but I did not get which are the rules when multiple lifetimes are involved. Could you please help me explaining what formally happens under the wood? Are there specific references on this topic?

like image 385
JtTest Avatar asked Dec 22 '25 14:12

JtTest


1 Answers

“Reborrowing” is unfortunately not well documented. However, the way I think it is useful to understand this is:

  • Whenever you borrow some place (regardless of whether that borrow is a “reborrow”, you may only do so for as long as you have the appropriate access to that place.

  • To determine how long you have access to a place, look at the references you have to follow to get to that place, from the inside out.

    • If you want to access a T to which you have a &'a T, then you may copy the &'a T and thereby obtain access with lifetime 'a. This is only a momentary access to the place containing the &'a T, so you can stop here; the lifetimes involved in reading out a copy don't matter.
    • If you want to access a T to which you have a &'a mut T then, since &mut references are exclusive, you must take an exclusive borrow of the place containing the &'a mut T to ensure exclusivity is not violated; 'a is merely an upper bound on how long your borrow can last, and you must repeat this whole process for the place containing the &'a mut T.

So, in your particular case of

let _c: &'s mut NotCopyable = &mut (*(self.c));

I would analyze this borrowing operation as follows:

  1. We are trying to exclusively borrow the NotCopyable located at *self.c.
  2. The place *self.c is a dereference of an &'a mut NotCopyable; therefore,
    • the borrow cannot last longer than 'a, and
    • we must exclusively borrow self.c (step 3).
  3. We are trying to exclusively borrow the &'a mut NotCopyable located at self.c.
  4. self is a &'s mut B<'a>, so we are trying to exclusively borrow from a &'s mut B<'a>. Therefore,
    • the borrow cannot last longer than 's, and
    • we must excluively borrow the local variable self.

So at the end of this process we have concluded that the new borrow may have any lifetime that is not longer than 'a or longer than 's. We know (via well-formedness rules) that 'a: 's, otherwise the reference &'s mut B<'a> could not validly exist. Therefore, it is sufficient to say that the new borrow may have any lifetime that is not longer than 's; and so we find that we can decide that this borrow shall have lifetime 's exactly.

like image 156
Kevin Reid Avatar answered Dec 24 '25 06:12

Kevin Reid



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!