How can I change fields of elements in vectors in Rust?

To mutate the first element of the vector you'd usually get a reference to that element. In other words, a reference into the vector. And being a normal structure the vector needs to have a method that would provide you with the reference.

Thing is, a reference into a vector means you can do something with the insides of the vector, read them or modify them in some way. Rust doesn't know the details, it just knows that while you're holding that reference, you can do stuff.

And with just that limited information the borrow checker of Rust tries to stop you from shooting yourself in the foot. It says: if you're going to read the vector, fine, you can read it any way you want, you can even make some other function read it, or two functions, or five. But you can't modify the vector while you're reading it, it isn't safe, it leads to bugs. So, you can have as many read-only references into the vector as you want, but only if and when you're not holding any writeable references into it. If you do hold a writeable reference, then there can be only one such reference at a time.

Thus the kind of reference matters. And that is why the vector has the two methods that give you the first element: first and first_mut.

So here

let mut vec = Vec::new();

your vector is already mutable. And coming from other languages you might work from intuition that if the vector is mutable once, it is mutable always. Kind of like const value in C++ or immutable in D. It's either mutable, or it's not.

But in Rust you might want immutable references into mutable structure. For instance, you might want one thread to work on one element of a vector and another thread on another element, and if you'd rather keep the borrow checker's safety belt on, then the simplest way to have multiple references is to keep them immutable. That is why methods like first return immutable references and to get a mutable reference you need to explicitly opt in by using a different method.

P.S. So was that any help?


Here's equally working code samples:

vec[0].some_value += 1;

vec.first_mut().unwrap().some_value += 1;

The issue with code that is shown in question is that first() returns an (immutable) reference to first element but mutable reference is required.

Indexing ([0]) works like this:

  1. vec derefs to slice
  2. indexing on slice calls index_mut method from IndexMut trait
  3. index_mut method returns mutable reference (&mut someType)

I think you're looking for &mut when taking reference.

#[derive(Debug)]
struct Character{
    name: String,
}

fn main() {
    let mut hobbits = vec![
        Character{name:String::from("Sam")},
        Character{name:String::from("Merry")},
        Character{name:String::from("Pepper")},
    ];

    {
        let third = &mut hobbits[2];
        third.name = String::from("Pippin");
    }

    println!("{:?}", hobbits);
}

Note {} around mutable element reference. It is required to limit mutable reference scope. Can't have mutable and immutable references at the same time: println! would fail while third is still in scope.

Tags:

Rust