#Start And End Of A Lifetime Of A Borrowed

6 messages · Page 1 of 1 (latest)

full valley
#

For the following code

#[cfg(test)]
pub(crate) mod demo {
    fn use_x(x: &X) {
        x.use();
    }
    
    #[test]
    fn demo1() {
        let x: X = X::rand();
        let xr1: &X;                           /*start here or*/
        {
            xr1 = &x;                          /*or start here*/
        }
        use_x(xr1);                            /*last use and end here*/
    }
    
    #[test]
    fn demo2() {
        let x: X = X::rand();
        let xr1: &X;                           /*start here or*/
        {
            xr1 = &x;                          /*or start here*/
            use_x(xr1);                        /*last use here*/ /*end here or*/
        }
                                               /*or end here*/
    }
}

At which lines does the lifetime of the borrowed xr1 start and end for both functions demo1 and demo2?
Note: Code successfully compiles and runs for both functions.

placid lion
#
  1. Lifetimes do not have start points at all. Lifetimes only track end points, in order to ensure nothing is used after it's dropped. Ensuring that nothing is used before it's dropped happens naturally because there is no way to obtain a “not valid yet” reference.
  2. Lifetimes also don't have specific end points all the time. The compiler only keeps track of constraints, like "xr1 must be valid when use_x(xr1) is called" and "x is dropped at the end of demo1", and produces an error if those constraints are actually violated somewhere. So, the answer to "where is the end" in your example is "here or there, I don't care".
#

(An abstract way to look at this is that the language never deals with “concrete lifetimes” at all, only “lifetime variables”, except for 'static, and the constraints are about what possible concrete lifetimes fit in those variables.)

full valley
#

I am not undermining what you are explaining. It just doesn't make sense when reasoning about code.
This is my attempt to answer my question.

mod _02_lifetimes_of_borrowed {
    /*
        Info:
            1.  This is an attempt to figure out the rules of the compiler when it comes to where the borrow lifetime starts and ends
            2.  This will be done for immutable borrow (rules should be the same for mutable borrow)
            3.  Mutable borrows will be injected in parts of the code where we are not sure if that part is a part of the immutable borrow lifetime.
            3.1.    If the part is indeed a part of the immutable borrow lifetime then the compiler will complain because we can't mix a mutable borrow with another borrow (immutable or mutable)
            3.2.    If the part is not a part of the immutable borrow lifetime then the compiler will not complain.
    */

    use crate::types::X;

    fn use_x(x: &X) {
        println!("Using ({:?})", x);
    }

    fn use_mutable_x(x: &mut X) {
        println!("Using ({:?}) mutably", x);
    }

    #[test]
    fn demo1() {
        let mut x: X = X::rand();

        let xr1: &X;                /*xr1 lifetime doesn't start here*/

        use_mutable_x(&mut x);      /*test to see where xr1 lifetime starts*/

        xr1 = &x;                   /*xr1 lifetime starts here*/

        use_x(xr1);                 /*xr1 lifetime ends here*/

        use_mutable_x(&mut x);      /*test to see where xr1 lifetime ends*/
    }
}
placid lion
#

you cannot just "test" where a lifetime ends

#

by using it at some point, you are adding a constraint that it is live at that point