2

I am trying to change the elements of a vector inside a closure:

pub struct Foo<'a, T> {
    cb: Box<dyn FnMut(Vec<T>) + 'a>,
}

impl<'a, T> Foo<'a, T> {
    pub fn new<F: FnMut(Vec<T>) + 'a>(cb: F) -> Self {
        Self { cb: Box::new(cb) }
    }

    pub fn fun(&mut self, v: T) {
        let vector = vec![v];
        (self.cb)(vector);
    }
}

fn main() {
    let mut a = Vec::new();
    let mut foo = Foo::new(move |v| {
        for i in v {
            a.push(i);
        }
    });
    foo.fun(1);
    println!("{:?}", a);
}

Playground

I'm getting an error:

error[E0382]: borrow of moved value: `a`
  --> src/main.rs:24:22
   |
17 |     let mut a = Vec::new();
   |         ----- move occurs because `a` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
18 |     let mut foo = Foo::new(move |v| {
   |                            -------- value moved into closure here
19 |         for i in v {
20 |             a.push(i);
   |             - variable moved due to use in closure
...
24 |     println!("{:?}", a);
   |                      ^ value borrowed here after move

I understand that Rust can't copy the value of a in the closure because Vec does not implement the trait Copy, so it has to move it, and moving a as mutable makes it unusable by println! later.

Am I storing the closure correctly? Is the use of the lifetime 'a correct here? Should I wrap the vector in something like Box or Cell?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Alex Covizzi
  • 971
  • 8
  • 9
  • 1
    Why have you chosen to require ownership of the `Vec` in the closure argument (`FnMut(Vec)`)? – Shepmaster Jan 21 '20 at 15:00
  • 1
    You can solve your problem by [removing the `move` and ensuring that the mutable borrow ends before the immutable borrow](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=ac35e57eaa2b08482679f01ea88b770f). – Shepmaster Jan 21 '20 at 15:04
  • What if i need to use `a` before `foo` is dropped? – Alex Covizzi Jan 21 '20 at 15:09
  • 1
    Then it's a duplicate of [Can't borrow mutably within two different closures in the same scope](https://stackoverflow.com/q/49703990/155423) – Shepmaster Jan 21 '20 at 15:10

1 Answers1

1

Here's the solution (playground):

pub struct Foo<'a, T> {
    cb: Box<dyn FnMut(Vec<T>) + 'a>,
}

impl<'a, T> Foo<'a, T> {

    pub fn new<F: FnMut(Vec<T>) + 'a>(cb: F) -> Self {
        Self {
            cb: Box::new(cb),
        }
    }

    pub fn fun(&mut self, v: T) {
        let vector = vec![v];
        (self.cb)(vector);
    }
}

fn main() {
    let mut a = Vec::new();

    // new scope to make sure that `foo` isn't alive when `a` is borrowed later
    {
        // no `move` to prevent moving `a` into the closure
        let mut foo = Foo::new(|v| {
            a = v.clone();
        });
        foo.fun(1);
    }
    println!("{:?}", a);
}
Aloso
  • 5,123
  • 4
  • 24
  • 41