RustArena

Rust error E0596: cannot borrow as mutable, as it is not declared as mutable

Fix Rust's E0596 error: add mut to the variable, take &mut in the function signature, or make a mutating closure mut.

E0596 means you tried to change something through a path that doesn't allow changes. In Rust, mutability is opt-in at every level: the variable must be let mut, and a reference must be &mut to be written through. The fix is to add mut in the right place, and rustc's help: line usually shows exactly where.

Case 1: the variable isn't mut

fn main() {
    let names = Vec::new();
    names.push("Ferris");
    println!("{names:?}");
}
error[E0596]: cannot borrow `names` as mutable, as it is not declared as mutable
 --> src/main.rs:3:5
  |
3 |     names.push("Ferris");
  |     ^^^^^ cannot borrow as mutable
  |
help: consider changing this to be mutable
  |
2 |     let mut names = Vec::new();
  |         +++

push takes &mut self, so calling it borrows names mutably. Write let mut names. The same applies to read_line(&mut line), sort(), insert, clear and every other method that changes its receiver.

Case 2: the parameter is & but the function modifies it

fn add_guest(list: &Vec<String>, name: &str) {
    list.push(name.to_string());
}

fn main() {
    let mut guests = Vec::new();
    add_guest(&guests, "Ferris");
    println!("{guests:?}");
}
error[E0596]: cannot borrow `*list` as mutable, as it is behind a `&` reference

A shared reference is read-only, no matter whether the original variable is mut. Change the signature to list: &mut Vec<String> and the call to add_guest(&mut guests, "Ferris"). Both sides must say mut: that's how readers of the call site know the function can change guests.

Case 3: a method takes &self but changes a field

Inside fn record(&self), self.hits += 1 fails with the closely related E0594, "cannot assign to self.hits, which is behind a & reference". Change the method to &mut self, and make the variable you call it on let mut. (If the method genuinely must stay &self, for example a cache inside a shared object, that's what Cell, RefCell and Mutex are for: interior mutability.)

Case 4: a closure that mutates a capture

fn main() {
    let mut count = 0;
    let bump = || count += 1;
    bump();
    println!("{count}");
}
error[E0596]: cannot borrow `bump` as mutable, as it is not declared as mutable

A closure that changes a captured variable is an FnMut, and calling it needs a mutable borrow of the closure itself: write let mut bump = || count += 1;.

Case 5: data inside Rc or behind an iterator

Don't over-correct

Adding mut where nothing changes produces the warning variable does not need to be mutable. The goal is that every mut in your code marks a place where something really changes.

Example

struct Counter {
    hits: u32,
}

impl Counter {
    fn record(&mut self) {
        self.hits += 1;
    }
}

fn add_guest(list: &mut Vec<String>, name: &str) {
    list.push(name.to_string());
}

fn main() {
    let mut names = Vec::new();
    names.push("Ferris");
    println!("{names:?}");

    let mut guests = Vec::new();
    add_guest(&mut guests, "Ferris");
    add_guest(&mut guests, "Corro");
    println!("{guests:?}");

    let mut counter = Counter { hits: 0 };
    counter.record();
    counter.record();
    println!("hits {}", counter.hits);

    let mut count = 0;
    let mut bump = || count += 1;
    bump();
    bump();
    println!("count {count}");

    let mut levels = vec![1, 2, 3];
    for lvl in &mut levels {
        *lvl *= 10;
    }
    println!("{levels:?}");
}

Output:

["Ferris"]
["Ferris", "Corro"]
hits 2
count 2
[10, 20, 30]

Practice it