Search code examples
rust

How does mutability work with Vec and elements within it?


I don't quite get the idea of mutability in Rust in the following situation:

  1. Mutable Vec with mutable elements
  2. Mutable Vec with immutable elements
  3. Immutable Vec with mutable elements
  4. Immutable Vec with immutable elements.

As far as I got it, if both are immutable (4) then it is just a read only vector. But as long as I make vector mutable, it doesn't matter if elements mutable or not...

With mutable vector I can always mutate elements even if I did not make them mutable...

let mut st1 = String::from("Some");
let mut st2 = String::from("Value");

let vec: Vec<&mut str> = vec![&mut st1, &mut st2];

Can someone explain in which situations above combinations should be used and if there are certain limits for each of them.

Thank you so much!


Solution

  • Reference of Reference and Mutability

    So first you need to understand, reference of reference

    let mut i: i32 = 0;
    {
        let mut r: &i32 = &i;
        *r += 1; //cannot assign to `*r`, which is behind a `&` reference
        let rr: &&i32 = &r;
        **rr += 1; // cannot assign to `**rr`, which is behind a `&` reference
        let mr: &mut &i32 = &mut r;
        **mr += 1; //cannot assign to `**mr`, which is behind a `&` reference
    }
    
    let mut m: &mut i32 = &mut i;
    *m += 1; // OK
    let rm: &&mut i32 = &m;
    **rm += 1; // cannot assign to `**rm`, which is behind a `&` reference
    let mm: &mut &mut i32 = &mut m;
    **mm += 1; // OK
    

    That mean that if you want to mutate a value behind two degrees of reference, you'll need both degrees to be a mutable reference.

    Example with Vec

    fn main() {
        let mut a: i32 = 0;
        let mut b: i32 = 0;
    
        // Immutable Vec with Immutable reference element
        {
            let v = vec![&a, &b];
            let _ = v.pop(); // cannot borrow as mutable
            *v[0] += 1; // cannot assign to data in an index of `Vec<&i32>`
        }
    
        // Mutable Vec with Immutable reference element
        {
            let mut v = vec![&a, &b];
            let _ = v.pop(); // you can mutate the vec itself
    
            *v[0] += 1; // but not the elements it referenced
            // ^^^^^^^
            // since, this is basically this
            // vvvvvvv
            let r: &mut &i32 = v.get_mut(0).unwrap();
            **r += 1;
            // cannot assign to `**r`, which is behind a `&` reference
        }
    
        // Immutable Vec with Mutable reference element
        {
            let v = vec![&mut a, &mut b];
            let _ = v.pop();
            *v[0] += 1;
    
            let r: &mut &mut i32 = v.get_mut(0).unwrap();
                                // ^ cannot mutate immutable variable `v`
                                // since v is immutable, you cannot mutably borrow v
            **r += 1;
        }
    
        // Mutable Vec with Mutable reference element
        {
            let mut v = vec![&mut a, &mut b];
            let _ = v.pop();
            *v[0] += 1;
    
            let r: &&mut i32 = v.get(0).unwrap();
            **r += 1;
            // cannot assign to `**r`, which is behind a `&` reference
    
            let r: &mut &mut i32 = v.get_mut(0).unwrap();
            **r += 1;
        }
    }