Mutable reference in block prevent reference outside the block

Hi Guys,

I'm calling a method to return a mutable reference in a block. As my understanding, the mutable reference should be invalid when the block ends and I should be able to use immutable reference again.
However, the compiler refused.

#[derive(Debug)]
pub struct X<'a> {
    data: &'a mut u64,
}

impl<'a: 'b, 'b> X<'a> {
    pub fn as_xref(&'a mut self) -> &'b mut X {
        self
    }
}

fn main() {
    let mut data: u64 = 5;
    let mut wrapper = X{data: &mut data};
    
    println!("{:?}", wrapper);
    
    {
        let r = wrapper.as_xref();
        
        *r.data += 3;
    }
    
    
    println!("{:?}", wrapper);

}

The error is as below:

 Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `wrapper` as immutable because it is also borrowed as mutable
  --> src/main.rs:25:22
   |
19 |         let r = wrapper.as_xref();
   |                 ------- mutable borrow occurs here
...
25 |     println!("{:?}", wrapper);
   |                      ^^^^^^^
   |                      |
   |                      immutable borrow occurs here
   |                      mutable borrow later used here
   |
   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)

When I tried to get the mutable reference with & operator, the thing is different and I don't understand why.

#[derive(Debug)]
pub struct X<'a> {
    data: &'a mut u64,
}

impl<'a: 'b, 'b> X<'a> {
    pub fn as_xref(&'a mut self) -> &'b mut X {
        self
    }
}

fn main() {
    let mut data: u64 = 5;
    let mut wrapper = X{data: &mut data};
    
    println!("{:?}", wrapper);
    
    {
        let r = &mut wrapper;
        
        *r.data += 3;
    }
    
    
    println!("{:?}", wrapper);

}
   Compiling playground v0.0.1 (/playground)
    Finished dev [unoptimized + debuginfo] target(s) in 0.44s
     Running `target/debug/playground`

X { data: 5 }
X { data: 8 }

This happens because you have strange lifetime requirements on as_xref. This is how it should be:

impl<'a> X<'a> {
    pub fn as_xref<'b>(&'b mut self) -> &'b mut X<'a> {
        self
    }
}

Which you can also write like this:

impl X<'_> {
    pub fn as_xref(&mut self) -> &mut Self {
        self
    }
}

It's pretty much impossible to use a value of type &'a mut X<'a>. &mut references need to live for less than what they point to.

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.