Trying to understand Mutability. Modify Reference vs. modify Object

57 Views Asked by At

I am trying to understand mutability.

When I declare a variable in Rust with

let mut a = String::from("Foo");

I can modify the Object, e.g.:

a.push_str("Bar");

Or assign a new Object, e.g:

a = String::from("Bar");

When I declare a variable without 'mut'

let a = String::from("Foo");

I can neither modify the Object nor assign a new Object.

So I can either choose to:

  1. have a mutable object with a mutable variable or
  2. have an immutable obejct with an immutable variable

I wonder if it is possible to declare vaiables so that

  1. the object is immutable, but the variable is mutable and can be assigned to a different object or
  2. the object is mutable, but the variable is immutable and cannot be assigned to a different object.

I read the chapter about mutability in the book but couln't find any information which could help me further.

2

There are 2 best solutions below

1
Chayim Friedman On BEST ANSWER

First, we need to make an important distinction:

In let mut, mut is a property of the binding, i.e. the variable. The variable and everything it contains can be mutated, but only as long as it contains it. We can transfer the content to another variable, and then mutability will be decided by the new one:

let v = String::from("Foo");
// Cannot mutate `v`.
v.clear(); // ERROR
v = String::new(); // ERROR

let mut new_v = v;
new_v.clear(); // OK
new_v = String::new(); // OK

In contrast, mutability of references (& and &mut) is a property of the value. Even if we transfer ownership, shared references cannot be mutated (unless they contain interior mutability).

Now, I can answer your questions:

the object is immutable, but the variable is mutable and can be assigned to a different object or

Yes, if we make the variable a shared reference:

let mut v = &String::from("Foo");
v.clear(); // ERROR
let other = String::new();
v = &other; // OK

the object is mutable, but the variable is immutable and cannot be assigned to a different object.

Yes, if an immutable variable contains a mutable reference:

let v = &mut String::from("Foo");
v.clear(); // OK
let mut other = String::new();
v = &mut other; // ERROR

Another way to satisfy (2), as already said, is using interior mutability:

let v = std::cell::RefCell::new(String::from("Foo"));
v.borrow_mut().clear(); // OK
v = String::new(); // ERROR
0
antaz On

In Rust, You can have interior mutability where the binding is immutable, but the object is mutable.

If the binding however is mutable then the object is also mutable.

You can create a mutable reference to an immutable T mut &T, this will allow you to mutate the binding, but not the object.