0

I am getting this issue, as the variables I am deconstructing are borrowed(?) and can't be used in another method. This sounds like a very typical use case but I am not sure how to solve it.

`➜  hello_cargo git:(master) ✗ cargo build
   Compiling hello_cargo v0.1.0 (/Users/johnny/Projects/hello_cargo)
error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:24:39
   |
24 |         let DBAndCFs { db: _, cfs } = self.db.lock().as_ref().unwrap();
   |                                       ^^^^^^^^^^^^^^                  - temporary value is freed at the end of this statement
   |                                       |
   |                                       creates a temporary which is freed while still in use
25 |         cfs.len()
   |         --------- borrow later used here
   |
   = note: consider using a `let` binding to create a longer lived value
`

Here is the code that generates this issue:

    use parking_lot::Mutex;
    
    struct CF {
        inner: *mut i32,
    }
    
    struct DBAndCFs {
        db: i32,
        cfs: Vec<CF>,
    }
    
    struct DB {
        db: Mutex<Option<DBAndCFs>>,
    }
    
    impl DB {
    
        pub fn open() -> DB {
            DB {
                db: Mutex::new(Some(DBAndCFs{ db: 0, cfs: Vec::new() } )),
            }
        }
        pub fn get(&self) -> usize {
            let DBAndCFs { db: _, cfs } = self.db.lock().as_ref().unwrap();
            cfs.len()
        }
    }
    fn main() {
        let db = DB::open();
        print!("{}", db.get());
    }
John Difool
  • 5,572
  • 5
  • 45
  • 80
  • As the error-message suggests, you'll need a `let` binding for the `MutexGuard`, so it doesn't get dropped at the end of the statement, invalidating the borrow on `Vec` before calling `.len()` on it. Something to the tune of `let db = self.db.lock(); db.as_ref().unwrap().cfs.len()` – user2722968 Feb 18 '22 at 08:15
  • Okay, so I can't use a deconstructor to assign quickly to two variables ? – John Difool Feb 18 '22 at 08:27
  • 1
    You can use the deconstruction syntax. But you can't keep the reference around when the mutex guard (returned by `lock()`) goes out of scope. Of course, you could just not deconstruct and call `.cfs.len()` on the result of the unwrap, all in one line. – Sebastian Redl Feb 18 '22 at 08:30
  • I asked a concise Question for common rust error `error[E0716]` [error E0716: temporary value dropped while borrowed (rust)](https://stackoverflow.com/questions/71626083/error-e0716-temporary-value-dropped-while-borrowed-rust). It links back to this Question. – JamesThomasMoon Mar 26 '22 at 07:27

1 Answers1

4

temporary value is freed at the end of this statement
consider using a let binding to create a longer lived value

So the compiler is telling you that self.db.lock() is a temporary that gets dropped too early, and that you can extend its lifetime with a let binding. The advice is so precise that you could even follow it without knowing what's going on:

let db = self.db.lock();
let DBAndCFs { db: _, cfs } = db.as_ref().unwrap();
cfs.len()

The reason here is that self.db.lock() creates a mutex guard, that keeps the mutex locked until it is dropped. If you give it a variable to live in, that variable will exist to the end of the scope (the next }), and the guard won't be dropped long enough for you to call cfs.len(). If you don't give it a variable to live in, it will live as a temporary, until the next ;. Since you're trying to keep a reference to cfs beyond that ;, you'd have a reference to something protected by a mutex without the mutex being locked, which can't be allowed.

The other way to do what you want to call len before your temporary lock guard is dropped:

self.db.lock().as_ref().unwrap().cfs.len()
Caesar
  • 6,733
  • 4
  • 38
  • 44
  • Best explanation i've read for a long time. the temp var to keep the lock `db` till it goes out of scope totally makes sense. Thanks! – John Difool Feb 18 '22 at 10:20