Help with mutability within move closure

Hi everyone,

I'm trying and failing to understand why the following code doesn't compile.

use std::sync::Arc;

struct Foo {
    bar: Vec<i32>
}

impl Foo {
    pub fn baz(&mut self, num: i32) {
        self.bar.push(num);
    }
}

fn main() {
    let mut foo = Foo { bar: vec!() };
    let arc_foo = Arc::new(foo);
    
    let quux_foo = arc_foo.clone();
    let quux = move |num| {
        quux_foo.baz(num);
    };
    
    quux(1);
    
    let print_foo = arc_foo.clone();
    println!("{:?}", print_foo.bar);
}

It produces the following error, but I'm not entirely sure how to read it.

error: cannot borrow immutable borrowed content as mutable
  --> <anon>:19:9
   |>
19 |>         quux_foo.baz(num);
   |>         ^^^^^^^^

Does this mean that quux_foo is immutable? I've tried using the mut keyword (let mut quux_foo) too. I guess my understanding of move closures is not quite there.

Here's the same code on Rust Playground: Rust Playground

Any help would be much appreciated! :slight_smile:

Yup!

It's not actually the move closure that's the issue, it's that Arc holds something that's immutable. If you want to mutate the insides of the arc, you'll need to put a Mutex or RwLock inside.

2 Likes

This is because Arc does not implement DerefMut. In simpler terms, it won't give you an &mut to modify the contained object through. This is because of Rust's particular opinion on shared references and mutability: they are mutually exclusive.

Because you're using Arc and a move closure, I assume you're tinkering with threads. In this case, you'll want to use a Mutex, which allows two or more threads with shared references to a value (e.g. through an Arc) to request mutable access to that value one at a time; concurrent attempts to modify will allow one thread to continue executing with a mutable reference while all the other threads are blocked.

The Mutex API docs helpfully include an example on usage. I also recommend the Rust Programming Language chapter on Concurrency for further reading.

2 Likes

@steveklabnik @DroidLogician Thanks so much for the quick and helpful responses! <3

That's good to know. I need to do more reading on Mutex/RwLock.

For anyone who finds this thread in the future, here's an updated example that actually compiles.

1 Like