Как правильно разделить ссылку между замыканиями, если значение превышает эти замыкания?
Я хочу поделиться ссылкой между двумя замыканиями; mutable в одном закрытии. Это искусственная ситуация, но я нахожу ее интересной в контексте изучения Rust.
Чтобы заставить это работать, я должен был использовать Rc
, Weak
, а также RefCell
, Есть ли более простой способ добиться этого?
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
struct Foo {
i: i32,
}
impl Foo {
fn get(&self) -> i32 {
self.i
}
fn incr(&mut self) {
self.i += 1
}
}
fn retry<O, N>(mut operation: O, mut notify: N) -> i32
where
O: FnMut() -> i32,
N: FnMut() -> (),
{
operation();
notify();
operation()
}
fn something(f: &mut Foo) {
let f_rc = Rc::new(RefCell::new(f));
let f_weak = Rc::downgrade(&f_rc);
let operation = || {
// f.get()
let cell = f_weak.upgrade().unwrap();
let f = cell.borrow();
f.get()
};
let notify = || {
// f.incr();
let cell = f_weak.upgrade().unwrap();
let mut f = cell.borrow_mut();
f.incr();
};
retry(operation, notify);
println!("{:?}", f_rc);
}
fn main() {
let mut f = Foo { i: 1 };
something(&mut f);
}
1 ответ
Решение
Подсчет ссылок здесь не нужен, потому что объект живет дольше, чем любое из замыканий. Вы можете сойти с рук:
fn something(f: &mut Foo) {
let f = RefCell::new(f);
let operation = || f.borrow().get();
let notify = || {
f.borrow_mut().incr();
};
retry(operation, notify);
println!("{:?}", f);
}
что довольно просто.
Использование RefCell
Однако необходимо перенести принудительное использование псевдонима XOR Aliasing с периода компиляции на время выполнения.