Reputation: 561
I'm trying to encapsulate some code to avoid repeating it, relating to borrowing data out of a Mutex and further operations thereupon (which I leave off of this question as out of scope, but are the motivating factors).
The following sample code complains that guard
does not live long enough. But that is precisely why I'm returning guard
in the structure designed expressly for that purpose.
Is this a limitation of the borrow checker? Any suggestions on working around this?
use std::sync::{Mutex,MutexGuard};
use std::ops::DerefMut;
pub struct InnerData {
count: i32 // sample only
}
pub struct Data {
pub inner_data: Mutex<InnerData>
}
pub struct BorrowedInnerData<'a> {
pub inner_data: &'a mut InnerData,
guard: MutexGuard<'a,InnerData>,
}
impl Data {
pub fn borrow_inner_data<'a>(&'a mut self) -> BorrowedInnerData<'a> {
let guard = self.inner_data.lock().unwrap();
BorrowedInnerData {
inner_data: guard.deref_mut(),
guard: guard,
}
}
}
fn main() {
let mut data = Data {
inner_data: Mutex::new( InnerData {
count: 5
}),
};
let borrowed_inner_data = data.borrow_inner_data();
}
Upvotes: 5
Views: 3456
Reputation: 430368
Let's look at the DerefMut
trait:
pub trait DerefMut: Deref {
fn deref_mut(&'a mut self) -> &'a mut Self::Target;
}
This means that when deref_mut
is called, a reference is returned that lives as long as the value being dereferenced. However, you are moving guard
when you move it to BorrowedInnerData
. This means that the value stops living at one memory location and starts at a new one. As Veedrac hints at, it's entirely possible that by moving the guard, you would invalidate the reference. This would be bad and lead to crashes (in the best case).
However, there's no real reason to keep guard
and inner_data
. Because of Deref
and DerefMut
, a MutexGuard<InnerData>
can be used just like a &InnerData
or &mut InnerData
. Simply remove inner_data
from your struct and keep guard
.
Upvotes: 7