I have a vec
of some struct type and I want to change some field of the first element in the vector. How can I do this?
Example:
struct SomeType {
some_value: i32,
}
fn main() {
let mut vec = Vec::new();
let mut t = SomeType { some_value: 45 };
vec.push(t);
println!("Old value: {}", vec.first().unwrap().some_value);
vec.first().unwrap().some_value += 1;
println!("New value: {}", vec.first().unwrap().some_value);
}
This fails to compile:
error: cannot assign to immutable field
--> vec.rs:15:2
|
15 | vec.first().unwrap().some_value += 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot mutably borrow immutable field
I can't get my head around the mutability stuff in Rust yet; what would be the correct approach here?
To remove all elements from a vector in Rust, use . retain() method to keep all elements the do not match. let mut v = vec![ "A", "warm", "fall", "warm", "day"]; let elem = "warm"; // element to remove v.
Vector is a module in Rust that provides the container space to store values. It is a contiguous resizable array type, with heap-allocated contents. It is denoted by Vec<T>. Vectors in Rust have O(1) indexing and push and pop operations in vector also take O(1) complexity.
In Rust, there are several ways to initialize a vector. In order to initialize a vector via the new() method call, we use the double colon operator: let mut vec = Vec::new();
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:
vec
derefs to sliceindex_mut
method from IndexMut
traitindex_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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With