Как правильно разделить ссылку между замыканиями, если значение превышает эти замыкания?

Я хочу поделиться ссылкой между двумя замыканиями; 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 с периода компиляции на время выполнения.

Другие вопросы по тегам