Perform callbacks, such as volatile loop borrowing

Foocan be changed using the method .modify():

struct Foo;
impl Foo {
    fn modify(&mut self) {}
}

Bar stores callback:

struct Bar<'a> {
   callback: Box<FnMut() + 'a>
}
impl<'a> Bar<'a> {
    fn new<F: FnMut() + 'a>(f: F) -> Bar<'a> {
        Bar {
            callback: Box::new(f)
        }
    }
}

init()takes a fragment Barand executes its callbacks:

fn init(bars: &mut [Bar]) {
    for b in bars {
        (*b.callback)();
    }
}

And now the most interesting:

  • Change Fooin the loop:

    fn main() {
        let mut foo = Foo;
    
        for _ in 0..10 {
            foo.modify();
        }
    }
    

    This works great; at each iteration, the loop is Foomutimously borrowed and called .modify().

  • Change Fooin callbacks:

    fn main() {
        let mut foo = Foo;    
    
        let mut bar1 = Bar::new(|| foo.modify());
        let mut bar2 = Bar::new(|| foo.modify());    
    
        init(&mut [bar1, bar2]);
    }
    

Try on the playground , it has an error:

error: cannot borrow `foo` as mutable more than once at a time [E0499]
    let mut bar2 = Bar::new(|| foo.modify());
                            ^~~~~~~~~~~~~~~
help: see the detailed explanation for E0499
note: borrow occurs due to use of `foo` in closure
    let mut bar2 = Bar::new(|| foo.modify());
                               ^~~
note: previous borrow of `foo` occurs here due to use in closure; the mutable borrow prevents subsequent moves, borrows, or modification of `foo` until the borrow ends
    let mut bar1 = Bar::new(|| foo.modify());
                            ^~~~~~~~~~~~~~~
note: previous borrow ends here
fn main() {
...
}
^

How to implement a similar guarantee for clause 2?

+4
source share
1 answer

You can use RefCell:

let foo = RefCell::new(Foo);

{
    let bar1 = Bar::new(|| foo.borrow_mut().modify());
    let bar2 = Bar::new(|| foo.borrow_mut().modify());
    init(&mut [bar1, bar2]);
}

let mut foo = foo.into_inner();//extract foo to use in external API

borrow_mut(), , .


Bar init(), foo init() modify():

...
struct Bar<'a> {
    callback: Box<FnMut(&mut Foo) + 'a>
}
impl<'a> Bar<'a> {
    fn new<F: FnMut(&mut Foo) + 'a>(f: F) -> Bar<'a> {
        Bar {
            callback: Box::new(f)
        }
    }
}

fn init(bars: &mut [Bar], arg:&mut Foo) {
    for b in bars {
        (*b.callback)(arg);
    }
}
...
let mut bar1 = Bar::new(|x| x.modify());
let mut bar2 = Bar::new(Foo::modify);//you can pass it without closure
init(&mut [bar1, bar2], &mut foo);
+2

All Articles