简体   繁体   中英

how to refactor rust code to resolve borrow that reference parent in closure?


trait OnUpdate {
    fn on_update(&mut self, x: &i32);
}
struct Foo {
    field: i32,
    cbs: Vec<Box<OnUpdate>>,
}

struct Bar {
    foos: Vec<Foo>,
}

impl Bar {
    fn call_foo_cb(&mut self) {
        self.foos
            .iter_mut()
            .for_each(|foo| foo.cbs.iter_mut().for_each(|cb| cb.on_update(&self.value(*foo)))) // compile error see below
            // .for_each(|foo| foo.cbs.iter_mut().for_each(|cb| cb.on_update(&10))) // works
    }

    fn value(&self, foo: Foo) -> i32 {
        foo.field + self.foos.len() as i32 // pretend some calculation based on the current foo and self
    }
}

The above code is to demonstrate my problem. I am new to rust and I am wondering what is the best way to refactor in idiomatic rust way.

Thanks in advance.

   --> src/lib.rs:348:23
    |
346 |         self.foos
    |         --------- mutable borrow occurs here
347 |             .iter_mut()
348 |             .for_each(|foo| foo.cbs.iter_mut().for_each(|cb| cb.on_update(&self.value(*foo))))
    |              -------- ^^^^^ immutable borrow occurs here                   ---- second borrow occurs due to use of `self` in closure
    |              |
    |              mutable borrow later used by call

Its easier for me to reason about this with for loops, so consider this equivalent:

for foo in &mut self.foos {
    for cb in &mut foo.cbs {
        cb.on_update(&self.value(foo));
    }
}

If the calculated value doesn't depend on cb , then it can be moved out of the loop:

for foo in &mut self.foos {
    let x = self.value(foo);
    for cb in &mut foo.cbs {
        cb.on_update(&x);
    }
}

And then, you can change out the mutable loop for one using indexes to avoid creating a mutable borrow until later:

for i in 0..self.foos.len() {
    let x = self.value(&self.foos[i]);
    for cb in &mut self.foos[i].cbs {
        cb.on_update(&x);
    }
}

This code assumes that the value function actually takes the Foo by reference since its not Copy or Clone .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM