0

I am recreating the arithmetic operations in binary by representing numbers with a vector of booleans. Since the size of each vector can vary, I made a function to match the length of each vector:

fn match_lengths(mut bit_vec0: Vec<bool>, mut bit_vec1: Vec<bool>) -> (Vec<bool>, Vec<bool>) {
    {
        let (mut shorter, longer) = if bit_vec0.len() < bit_vec1.len() {
            (&bit_vec0, &bit_vec1)
        } else {
            (&bit_vec1, &bit_vec0)
        };
        let bit_sign = match shorter.last() {
            Some(content) => *content,
            None => false,
        };

        for _ in shorter.len()..longer.len() {
            shorter.push(bit_sign);
        }
    }

    (bit_vec0, bit_vec1)
}

I get the error

error[E0596]: cannot borrow immutable borrowed content `*shorter` as mutable
  --> src/main.rs:15:13
   |
15 |             shorter.push(bit_sign); // Error here
   |             ^^^^^^^ cannot borrow as mutable

Even though I declared it with the mut specifier.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Davraine
  • 5
  • 1
  • The next time you have an error, I suggest using your favorite search engine to search for the error text. Many times, an existing Stack Overflow question will be the top result (especially if you limit your search to this domain). – Shepmaster Nov 11 '17 at 22:04

1 Answers1

2

The type of shorter is a reference, more precisely a &Vec<bool>, which means it refers to a Vec<bool> which it is not allowed to mutate1.

Declaring the variable as mut shorter only makes the shorter variable mutable, allowing you to e.g. use shorter = ... assignment to make it refer to a different Vec<bool>. Regardless of the variable's mutability, a shared reference of type &Vec<bool> is not allowed to mutate the object it refers to.

What you need to do is make a mutable reference of type &mut Vec<bool>, using &mut bit_vec0 and &mut bit_vec1. This change makes the code compile, and at that point shorter no longer needs to be mut.

Finally, and this is unrelated to the question, match_lengths accepts bit_vec0 and bit_vec1 by value, modifies them, and returns them. Although that certainly works, it is more idiomatic to accept mutable references. Such an approach is more ergonomic for the caller, and more clearly signals the fact that the function doesn't really "return" anything, it really modifies existing objects.

With those modifications, the function looks like this:

fn match_lengths(bit_vec0: &mut Vec<bool>, bit_vec1: &mut Vec<bool>) {
    let (shorter, longer) = if bit_vec0.len() < bit_vec1.len() {
        (bit_vec0, bit_vec1)
    } else {
        (bit_vec1, bit_vec0)
    };
    let bit_sign = match shorter.last() {
        Some(content) => *content,
        None => false,
    };
    for _ in shorter.len()..longer.len() {
        shorter.push(bit_sign);
    }
}

1 This sounds much like C++'s const, but the guarantee in Rust is even stronger than that of const: not only is a shared (non-mut) reference not allowed to mutate the object it refers to, but neither is anyone else! Rust's compiler and runtime prevent creation of a mut reference to an object while any shared references to that object exist.

user4815162342
  • 141,790
  • 18
  • 296
  • 355