rustborrow-checkerrefcell

Rust : drop(&RefMut) instead of drop(RefMut)?


I know when borrowing a value from a RefCell, I can manually drop it to end this borrow.

However, if I use the reference to a RefMut instead of directly using the RefMut, the drop trait seems invalid to end this borrow.

So, what happend when trying to drop the &RefMut ? and why the RefMut will not be dropped during this operation. If the referenced RefMut is not dropped, when will it be dropped ?

use std::cell::RefCell;

struct Data {
    pub x: usize,
}

fn main() {
    let c = RefCell::new(Data { x: 42 });
    let b = &c.borrow_mut();
    drop(b);
    let mut d = c.borrow_mut();
    d.x = 43;
    println!("Hello, world!");
}

output

thread 'main' panicked at 'already borrowed: BorrowMutError', src/main.rs:11:19
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Solution

  • References can only exist if the value they reference also exists somewhere. In C/C++ it would be undefined behaviour to create a reference to a temporary that doesn't get stored in a variable. In Rust, however, it is legal, and an invisible variable gets created in the background that lives until the end of the current scope. This is called temporary lifetime extension. More info can be seen here.

    You can limit its lifetime by introducing another scope:

    use std::cell::RefCell;
    
    struct Data {
        pub x: usize,
    }
    
    fn main() {
        let c = RefCell::new(Data { x: 42 });
        {
            let b = &c.borrow_mut();
            drop(b);
        }
        let mut d = c.borrow_mut();
        d.x = 43;
        println!("Hello, world!");
    }
    
    Hello, world!
    

    Or by storing it in a named variable instead:

    use std::cell::RefCell;
    
    struct Data {
        pub x: usize,
    }
    
    fn main() {
        let c = RefCell::new(Data { x: 42 });
    
        let b_val = c.borrow_mut();
        let b = &b_val;
        drop(b);
        drop(b_val);
    
        let mut d = c.borrow_mut();
        d.x = 43;
        println!("Hello, world!");
    }
    
    Hello, world!