I've been fighting with the borrow checker for a little bit... the gist of what I want to do is this:
#[derive(Debug)]
struct SomeStruct {
value: String,
}
impl SomeStruct {
fn new(value: &str) -> SomeStruct {
SomeStruct { value: value.to_string() }
}
fn change_value(&mut self, new_value: &str) {
self.value = new_value.to_string();
}
}
fn main() {
let mut my_vec = vec![
SomeStruct::new("foo"),
SomeStruct::new("bar"),
];
my_vec[0].change_value(my_vec[1].value.as_str());
}
This is a very generic version of a problem I'm having. Here's the stderr:
error[E0502]: cannot borrow `my_vec` as immutable because it is also borrowed as mutable
--> src/main.rs:22:30
|
22 | my_vec[0].change_value(my_vec[1].value.as_str());
| ------ ^^^^^^ - mutable borrow ends here
| | |
| | immutable borrow occurs here
| mutable borrow occurs here
So the borrow checker doesn't allow me to borrow the vector twice (once as mutable, and then again as immutable), which I understand. But the frustrating thing is that I want to modify one element in the vector, and only read another. I'm new to Rust (surprise!), and I'm not sure I've wrapped my mind around all its details and design choices. But this is something that feels like it should work, yet doesn't. What am I missing, and what can I do to get this (or comparable behavior) to work? Any help is greatly appreciated!
I agree, this is slightly confusing. So let's first see, why this is not allowed by the Rust compiler.
The index operator []
is something that can be overloaded, which means that users of the language can specify how it works. Rust tries to minimize the number of types of which the compiler has some special knowledge. As a consequence and despite its popularity, Vec<T>
is just a normal type defined by a library. You could write your own Vec<T>
without telling the compiler about it!
Vec<T>
also overloads the index operator, to allow indexing a vector. But since the overload could do anything, it could always return the first element of the vector! And if you assume the index operator would do such a strange thing, this code shouldn't be allowed:
my_vec[0].change_value(my_vec[1].value.as_str());
Because my_vec[0]
and my_vec[1]
reference the same value.
Of course, the index operator is not implemented in such a stupid fashion and we know that. In order to get two references to different elements of the vector (where at least one is mutable), we have to use some special functions instead of the index operator. And there are quite some ways to do it:
split_first_mut()
split_at_mut()
iter_mut()
which returns an iterator over mutable referencesI can't really tell you what method to use, because I don't know your exact use case. But just to fix your example, you can write:
let (head, tail) = my_vec.split_first_mut();
head.change_value(tail[0].value.as_str());
You're right, you can't borrow an object both immutably and mutably at the same time; in order to get this working you can do the following:
let new_value = my_vec[1].value.clone();
my_vec[0].change_value(&new_value);
When you clone()
the value
from myvec[1]
, you are no longer borrowing myvec
and are free to use the new_value
in the next line.
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