Rc: How to get a mutable reference to pass to get_mut

I am experimenting with Rc and have written this simple program.

use std::collections::HashMap;
use std::rc::Rc;

fn main() {
    // Create initial HashMap
    let mut register: HashMap<String, Rc<Vec<&str>>> = HashMap::new();
    register.insert(
        String::from("colours"), Rc::new(vec!["red", "green", "blue"]),
    );
    register.insert(
        String::from("beverages"), Rc::new(vec!["coffee", "tea", "juice"]),
    );
    println!("Register: {:?}", register);

    // rc_ref should be a MUTABLE reference to the Rc that wraps the Vec;
    // however, the IDE confirms it is of type &std::rc::Rc<std::vec::Vec<&str>>
    // (that is, NOT mutable)
    let mut rc_ref = register.get(&String::from("colours")).unwrap();

    // Rc::get_mut expects a &mut std::rc::Rc<_>
    let _list = Rc::get_mut(rc_ref);
}

Somehow I cannot work out how to get a mutable reference to pass into the get_mut function. I am getting the following compiler error.

error[E0308]: mismatched types
  --> src/main.rs:26:29
   |
26 |     let _list = Rc::get_mut(rc_ref);
   |                             ^^^^^^ types differ in mutability
   |
   = note: expected mutable reference `&mut std::rc::Rc<_>`
                      found reference `&std::rc::Rc<std::vec::Vec<&str>>`

Could someone please give me a hint? Thank you.

The HashMap::get method returns an immutable reference, so you get an immutable reference. If you want a mutable one, use HashMap::get_mut. The mut you put on the variable doesn't make the reference mutable, rather it allows you to change which reference is stored in the variable, e.g. you can do this:

let mut rc_ref = register.get("colours").unwrap();
// change it to some other reference
rc_ref = register.get("beverages").unwrap();

Be aware that the Rc::get_mut method only works if there are no other Rcs to the same value.

1 Like

If this is a problem for your application, Rc::make_mut() is a possible alternative. Where get_mut would fail, it clone()s the value instead. You now have two distinct objects, which might be acceptable.

Otherwise, you'll need to use something like Rc<RefCell<_>> to verify at runtime that only one mutable reference exists at a time.

Thank you, alice. So, I think this is where I am getting confused. (I do understand pointers; have programmed C for quite some time, but these mutable/immutable references do my head in somehow.) Let me repeat this in my own words:

register.get("colours").unwrap();

returns a mutable reference to the value in the HashMap—the Rc holding the Vector—regardless of the mutable/immutable status of the variable on the left-hand-side that I might assign this to. I guess the confusion is somehow in the (natural; not programming) language, right? When we say "rc_ref is a mutable reference to the value in the Hashmap" we could mean one of two things, right?

1 - rc_ref is mutable, as in let mut rc_ref; that is, we can modify where this reference points to; or
2 - the target of rc_ref is mutable; as in rc_ref is of type &mut std::rc::Rc<_>

Does that make sense? Or do I have my wires cross here?

Also, if I rewrite the line using .get_mut but leaving the variable non-mut, like so

let rc_ref = register.get_mut(&String::from("colours")).unwrap();

...what I can I now do that I could not do before in my original version (where I just used .get). In other words, what does that mutable reference to the Rc gain me?

Thank you so much for your patience.

No, HashMap::get returns an immutable reference.

Yeah those are the two options. If you say "rc_ref is a mutable reference to the value in the HashMap" I will understand it as the second option and not the first.

If your variable binding is not marked mut, you cannot really use the mutable powers of the mutable reference you have. This is because marking something immutable in Rust is "recursive" or "deep", i.e. if you have immutable access to a mutable reference, you cannot mutate through that reference.

Not sure what do you mean here, since this code works:

fn main() {
    let mut v = vec![];
    let v_ref = &mut v;
    *v_ref = vec!["test"];
    println!("{:?}", v);
}

Playground

This is a quirk of the Rust language: Usually variables containing something like mutable references need to be mutable themselves in order to use them. E.g. a MutexGuard is usually assigned to a mut variable for this reason. But mutable references themselves are a bit special in that they don’t need to be in a mutable variable in order to mutate their target through them. I guess the reason for this is so that it is not required to type out the word mut all that often in something like

let mut v_ref = &mut v;
// unnecessary first `mut` as long as you don’t want
// to change where the reference is pointing

As soon as the &mut reference is inside a struct or used in a non-trivial manner (i.e. something other than direct *v_ref style dereferencing), things become more interesting though, uncovering some other quirks of the Rust language, too.

Click here to expand some in-depth explanation/examples of what kind of quirks I’m referring to!

First example, reborrowing:

fn foo(r: &mut i32) -> &mut i32 {r}

let mut x = 0;
let x_ref = &mut x;
let r = foo(x_ref);
// *x_ref += 1; // illegal here
*r += 1;
*x_ref += 1;

in order to make more programs compile, Rust ensures that passing x_ref to a function like that does not just move the mutable reference into foo (note how the last line can still access x_ref). But also, the call to foo is not just implicitly ordinarily borrowing x_ref. (If it was immutably borrowing x_ref then the resulting & &mut i32 could not be used to get back a &mut i32 again, but mutably borrowing x_ref doesn’t work either because it isn’t a mut variable.) Instead what’s happening here is that x_ref is re-borrowed. Note the error message if the 5th line is uncommented:

error[E0503]: cannot use `*x_ref` because it was mutably borrowed
 --> src/main.rs:7:1
  |
6 | let r = foo(x_ref);
  |             ----- borrow of `*x_ref` occurs here
7 | *x_ref += 1; // illegal here
  | ^^^^^^^^^^^ use of borrowed `*x_ref`
8 | *r += 1;
  | ------- borrow later used here

It only talks about borrowing *x_ref and ignores the question of what actually happened to the x_ref reference. To understand this, one should note that in fact the call foo(x_ref) is equivalent to foo(&mut *x_ref).

Second example, mutable references inside structs vs enums

This compiles

let mut x = 0;
let y = (&mut x, 0);
*y.0 += 1;
*y.0 += 1; // do this twice to make sure that `y.0` was not moved

as does this

struct S<A> {
    field1: T<A>,
    some_more_fields: u32,
}
struct T<A> {
    a: A,
    blah: bool,
}

let mut x = 0;
let y = S {
    some_more_fields: 42,
    field1: T {
        a: &mut x,
        blah: false,
    }
};
*y.field1.a += 1;
*y.field1.a += 1; // do this twice to make sure that `y.0` was not moved

but try modifying x through y in this situation

let mut x = 0;
let y = Some(&mut x);

You’ll find that match doesn’t easily allow you the same kind of direct access to fields as .field notation gives you (and direct field access isn’t possible for enums). Let’s try a few approaches to modify x through y without moving out of y or changing y to be mut.

let mut x = 0;
let y = Some(&mut x);
match y { // moves out of y
    Some(x_ref) => *x_ref += 1,
    _ => {}
}
/* so a second time won’t work
match y { // moves out of y
    Some(x_ref) => *x_ref += 1,
    _ => {}
}
*/
let mut x = 0;
let mut y = Some(&mut x);
match &mut y { // obviously needs `mut y`
    Some(x_ref) => **x_ref += 1,
    _ => {}
}
match y { // works a second time now
    Some(x_ref) => *x_ref += 1,
    _ => {}
}
let mut x = 0;
let y = Some(&mut x);
match y {
    Some(&mut x_ref) => x_ref += 1,
    // doesn’t work but suggests to write `mut x_ref`
    _ => {}
}
// compiles but doesn’t actually modify x
// (there’s some useful warnings that make this obvious even without the print)
let mut x = 0;
let y = Some(&mut x);
match y {
    Some(&mut mut x_ref) => x_ref += 1,
    _ => {}
}
println!("{}", x); // prints 0

so, this took me a while to come up with but it does work

let mut x = 0;
let y = Some(&mut x);
match y {
    Some(&mut ref mut x_ref) => *x_ref += 1,
    _ => {}
}
match y {
    Some(&mut ref mut x_ref) => *x_ref += 1,
    _ => {}
}
println!("{}", x); // prints 2

Third example, closures and unique immutable borrows:

This compiles / works

let mut x = 0;
let mut y = 0;
let z = (&mut x, &mut y);
println!("{}", std::mem::size_of_val(&z)); // prints 16 on Rust playground

let mut closure1 = || {
    *z.0 += 1;
    *z.1 -= 1;
};
println!("{}", std::mem::size_of_val(&closure1)); // prints 8 on Rust playground
// so the closure only contains reference to `z`

closure1();
let mut closure2 = || {
    *z.0 += 1;
    *z.1 -= 1;
};
closure2();
println!("{}, {}", x, y); // prints 2, -2

which is a bit weird since closure1 is apparently capturing z by reference but through an immutable reference to z, x and y could not be modified, and a mutable borrow is not possible.

We can learn more by trying something illegal

// does not compile
let mut x = 0;
let mut y = 0;
let z = (&mut x, &mut y);

let mut closure1 = || {
    *z.0 += 1;
    *z.1 -= 1;
};

let mut closure2 = || {
    *z.0 += 1;
    *z.1 -= 1;
};

closure1(); // illegal
closure2();

Error:

error[E0524]: two closures require unique access to `z` at the same time
  --> src/main.rs:12:20
   |
7  | let mut closure1 = || {
   |                    -- first closure is constructed here
8  |     *z.0 += 1;
   |      - first borrow occurs due to use of `z` in closure
...
12 | let mut closure2 = || {
   |                    ^^ second closure is constructed here
13 |     *z.0 += 1;
   |      - second borrow occurs due to use of `z` in closure
...
17 | closure1(); // illegal
   | -------- first borrow later used here

Note how this error message is different from the error when you try to mutably borrow through closures, e.g.

// does not compile
let mut x = 0;

let mut closure1 = || {
    x += 1;
};

let mut closure2 = || {
    x += 1;
};

closure1(); // illegal
closure2();
error[E0499]: cannot borrow `x` as mutable more than once at a time
  --> src/main.rs:9:20
   |
5  | let mut closure1 = || {
   |                    -- first mutable borrow occurs here
6  |     x += 1;
   |     - first borrow occurs due to use of `x` in closure
...
9  | let mut closure2 = || {
   |                    ^^ second mutable borrow occurs here
10 |     x += 1;
   |     - second borrow occurs due to use of `x` in closure
...
13 | closure1(); // illegal
   | -------- first borrow later used here

What’s happening here is a special kind of borrow called unique immutable borrow that only happens like this in closures.

AFAIK that's not a quirk - just a consequence of the (obvious) fact that binding must be mut to create an exclusive reference to bound variable. For MutexGuard and the like, to get the inner reference, we use DerefMut, so the usage desugars to something like &mut DerefMut::deref_mut(&mut guard) - and to make this &mut guard, of course, guard must be mutable.

Hm, maybe the word “quirk” is not optimal. What I mean is: accessing a &mut T like this is somewhat of a special-case thing, dereferencing a mutable-reference-like type without the reference itself being in a mut variable (or a temporary) is something that only works with &mut T but not with any smart references (like the mutex guard, etc) because DerefMut is defined the way it is -- okay, well.. -- but DerefMut is defined the way it is because there is no way to write any abstraction around the kind of unique-but-not-mutable access you can have to a &mut T reference.

Even direct field accesses in this kind of “only the target is mutable” manner are hard (see my previous comment) and you can’t write a method for a struct/enum that allows this kind of access to re-borrow its &mut field without mutably borrowing the whole struct/enum. Which means the variable holding the struct/enum usually has to be mut.

That’s also why reborrowing is kind-of magical and closures have the unique immutable borrows as I explained in my previous comment.


Going further, let’s start with the fact that the best way to think about &mut T is that it (only) means “unique reference/borrow” anyways. (Otherwise, e.g. interior mutability is kind-of confusing.)

And since let mut x = ... means that the variable x admits creating &mut references to it, let mut x = ... would actually mean: it is possible to create unique borrows of x (where the uniqueness is compile-time-enforced).

In this mental model, all my examples of re-borrows, dereferencing of &mut T references in non-mut variable (or the field of a non-mut variable) or “unique immutable borrows” are pretty much quirks that enable you to archieve a unique borrow of a non-mut variable anyways.

Thank you for engaging in this. I have written some Rust code and read the book, but I still find that my mental model of variables/values and references is not solid and that makes internal mutability hard to understand. Just found this article here, which sheds some light on this.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.