I'm attempting to store a reference to an element of a mutable vector to use later. However, once I mutate the vector, I can no longer use the stored reference. I understand that this is because borrowing reference to the element also requires borrowing a reference to the vector itself. Therefore, the vector cannot be modified, because that would require borrowing a mutable reference, which is disallowed when another reference to the vector is already borrowed.
Here's a simple example
struct Person {
name: String,
}
fn main() {
// Create a mutable vector
let mut people: Vec<Person> = ["Joe", "Shavawn", "Katie"]
.iter()
.map(|&s| Person {
name: s.to_string(),
})
.collect();
// Borrow a reference to an element
let person_ref = &people[0];
// Mutate the vector
let new_person = Person {
name: "Tim".to_string(),
};
people.push(new_person);
// Attempt to use the borrowed reference
assert!(person_ref.name == "Joe");
}
which produces the following error
error[E0502]: cannot borrow `people` as mutable because it is also borrowed as immutable
--> src/main.rs:21:5
|
15 | let person_ref = &people[0];
| ------ immutable borrow occurs here
...
21 | people.push(new_person);
| ^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
...
24 | assert!(person_ref.name == "Joe");
| --------------- immutable borrow later used here
I've also tried boxing the vector elements as suggested here, but that doesn't help. I thought it might allow me to drop the reference to the vector while maintaining a reference to the element, but apparently not.
struct Person {
name: String,
}
fn main() {
// Create a mutable vector
let mut people: Vec<Box<Person>> = ["Joe", "Shavawn", "Katie"]
.iter()
.map(|&s| {
Box::new(Person {
name: s.to_string(),
})
})
.collect();
// Borrow a reference to an element
let person_ref = people[0].as_ref();
// Mutate the vector
let new_person = Box::new(Person {
name: "Tim".to_string(),
});
people.push(new_person);
// Attempt to use the borrowed reference
assert!(person_ref.name == "Joe");
}
This still produces the same error
error[E0502]: cannot borrow `people` as mutable because it is also borrowed as immutable
--> src/main.rs:23:5
|
17 | let person_ref = people[0].as_ref();
| ------ immutable borrow occurs here
...
23 | people.push(new_person);
| ^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
...
26 | assert!(person_ref.name == "Joe");
| --------------- immutable borrow later used here
Is there a way to do this, or am I trying to do something impossible?
I found that using a reference counted smart pointer allows me to accomplish what I'm attempting. It makes sense that a shared ownership is necessary, because otherwise the element reference would become invalid if the original vector were to go out of scope (which would deallocate the element, with or without the Box
).
The following code compiles successfully.
use std::rc::Rc;
struct Person {
name: String,
}
fn main() {
// Create a mutable vector
let mut people: Vec<Rc<Person>> = ["Joe", "Shavawn", "Katie"]
.iter()
.map(|&s| {
Rc::new(Person {
name: s.to_string(),
})
})
.collect();
// Borrow a reference to an element
let person_ref = Rc::clone(&people[0]);
// Mutate the vector
let new_person = Rc::new(Person {
name: "Tim".to_string(),
});
people.push(new_person);
// Attempt to use the borrowed reference
assert!(person_ref.name == "Joe");
}
If anyone else has any corrections, improvements or further insight, I'd be glad to hear it. But if not, I feel satisfied with this answer for now.