Допустим, у нас есть некая мутабельная структура данных (в данном случае это просто число, но это лишь для простоты примера), которую мы хотим шарить между потоками. При этом мы хотим сделать свою RAII обёртку над блокировкой этой сущности, чтобы предоставить пользователю определённый интерфейс её модификации (а также отслеживать разблокировку и т. п.).
Получается как-то так (лайфтаймы у обёртки от балды, потому что я не знаю как это правильно написать):
use std::sync::{Arc, Mutex, MutexGuard};
pub struct SharedData {
data: Arc<Mutex<i32>>
}
impl SharedData {
pub fn new(value: i32) -> Self {
SharedData {
data: Arc::new(Mutex::new(value))
}
}
pub fn lock(&self) -> LockedSharedData<'_> {
LockedSharedData::new(self.data.clone())
}
}
pub struct LockedSharedData<'a> {
_data: Arc<Mutex<i32>>,
guard: MutexGuard<'a, i32>
}
impl<'a> LockedSharedData<'a> {
fn new(data: Arc<Mutex<i32>>) -> Self {
LockedSharedData {
guard: data.lock().unwrap(),
_data: data
}
}
pub fn get(&self) -> i32 {
*self.guard
}
pub fn inc(&mut self) {
*self.guard += 1;
}
}
Оно ожидаемо не компилируется - https://rust.godbolt.org/z/4rEe3fWxK :
error[E0515]: cannot return value referencing function parameter `data`
--> <source>:26:9
|
26 | / LockedSharedData {
27 | | guard: data.lock().unwrap(),
| | ----------- `data` is borrowed here
28 | | _data: data
29 | | }
| |_________^ returns a value referencing data owned by the current function
error[E0505]: cannot move out of `data` because it is borrowed
--> <source>:28:20
|
24 | impl<'a> LockedSharedData<'a> {
| -- lifetime `'a` defined here
25 | fn new(data: Arc<Mutex<i32>>) -> Self {
26 | / LockedSharedData {
27 | | guard: data.lock().unwrap(),
| | ----------- borrow of `data` occurs here
28 | | _data: data
| | ^^^^ move out of `data` occurs here
29 | | }
| |_________- returning this value requires that `data` is borrowed for `'a`
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0505, E0515.
For more information about an error, try `rustc --explain E0505`.
Compiler returned: 1
Собственно, вопрос как это переписать правильно, чтобы Rust устраивали лайфтаймы, но при этом сохранить инкапсуляцию заблокированного значения в структуру блокировки.