rustborrow-checkerownership

rustlings move_semantics2 why passing reference doest not work?


i am trying Rust by doing the restlings exercices that is a very good approach to start with but there is something that i do not understand.

Exercice: move_semantics2

I understand that in order to initialize vec1 with the content of vec0 without taking the ownership away we have to either clone vec0 or to pass by reference. The issue is that this code, that passes references doesn't seem to work.

I wanna understand why, any idea ?

// move_semantics2.rs
// Make me compile without changing line 13 or moving line 10!
// Execute `rustlings hint move_semantics2` or use the `hint` watch subcommand for a hint.

// I AM NOT DONE

fn main() {
    let vec0 = Vec::new();

    let mut vec1 = fill_vec(&vec0);

    // Do not change the following line!
    println!("{} has length {} content `{:?}`", "vec0", vec0.len(), vec0);

    vec1.push(88);

    println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
}

fn fill_vec(vec: &Vec<i32>) -> &Vec<i32> {
    let mut vec = vec;

    vec.push(22);
    vec.push(44);
    vec.push(66);

    vec
}

this is the error i am getting :

⚠️  Compiling of exercises/move_semantics/move_semantics2.rs failed! Please try again. Here's the output:
warning: variable does not need to be mutable
 --> exercises/move_semantics/move_semantics2.rs:8:9
  |
8 |     let mut vec1 = fill_vec(&vec0);
  |         ----^^^^
  |         |
  |         help: remove this `mut`
  |
  = note: `#[warn(unused_mut)]` on by default

error[E0596]: cannot borrow `*vec1` as mutable, as it is behind a `&` reference
  --> exercises/move_semantics/move_semantics2.rs:13:5
   |
8  |     let mut vec1 = fill_vec(&vec0);
   |         -------- consider changing this binding's type to be: `&mut Vec<i32>`
...
13 |     vec1.push(88);
   |     ^^^^^^^^^^^^^ `vec1` is a `&` reference, so the data it refers to cannot be borrowed as mutable

warning: variable does not need to be mutable
  --> exercises/move_semantics/move_semantics2.rs:19:9
   |
19 |     let mut vec = vec;
   |         ----^^^
   |         |
   |         help: remove this `mut`

error[E0596]: cannot borrow `*vec` as mutable, as it is behind a `&` reference
  --> exercises/move_semantics/move_semantics2.rs:21:5
   |
19 |     let mut vec = vec;
   |         ------- consider changing this binding's type to be: `&mut Vec<i32>`
20 |
21 |     vec.push(22);
   |     ^^^^^^^^^^^^ `vec` is a `&` reference, so the data it refers to cannot be borrowed as mutable

error[E0596]: cannot borrow `*vec` as mutable, as it is behind a `&` reference
  --> exercises/move_semantics/move_semantics2.rs:22:5
   |
19 |     let mut vec = vec;
   |         ------- consider changing this binding's type to be: `&mut Vec<i32>`
...
22 |     vec.push(44);
   |     ^^^^^^^^^^^^ `vec` is a `&` reference, so the data it refers to cannot be borrowed as mutable

error[E0596]: cannot borrow `*vec` as mutable, as it is behind a `&` reference
  --> exercises/move_semantics/move_semantics2.rs:23:5
   |
19 |     let mut vec = vec;
   |         ------- consider changing this binding's type to be: `&mut Vec<i32>`
...
23 |     vec.push(66);
   |     ^^^^^^^^^^^^ `vec` is a `&` reference, so the data it refers to cannot be borrowed as mutable

error: aborting due to 4 previous errors; 2 warnings emitted

For more information about this error, try `rustc --explain E0596`.

Solution

  • I think your misconception stems from this line in fill_vec():

    let mut vec = vec;
    

    That line is not making a copy of the original vector, instead it tries to make the original immutable reference to the passed in vector mutable, which naturally the compiler does not allow. If your intent was to make a copy of the the passed-in vector, you would want your function to look like this:

    fn fill_vec(vec: &Vec<i32>) -> Vec<i32> {
        let mut new_vec = vec.clone();
    
        new_vec.push(22);
        new_vec.push(44);
        new_vec.push(66);
    
        new_vec
    }
    

    Note that this new version uses clone() to copy the original vector, and instead of returning a reference to a vector, it returns a new vector.