I run into similar problems related to ownership/borrowing every time I use Rust, so here is the simplest piece of code that illustrates my usual problems:
use std::cell::RefCell;
struct Res {
name: String,
}
impl Res {
fn new(name: &str) -> Res {
Res {
name: name.to_string(),
}
}
// I don't need all_res to be mutable
fn normalize(&mut self, all_res: &Vec<Res>) {
// [...] Iterate through all_res and update self.name
self.name = "foo".to_string();
}
}
fn main() {
let res = RefCell::new(vec![Res::new("res1"), Res::new("res2")]);
for r in res.borrow_mut().iter_mut() {
// This panics at runtime saying it's
// already borrowed (which makes sense, I guess).
r.normalize(&*res.borrow());
}
}
After reading about RefCell
I thought this would work. It compiles, but panics at runtime.
How do I reference a vector while iterating over the same vector? Is there any better data structure to allow me to do this?
First, we change s to be mut . Then we create a mutable reference with &mut s where we call the change function, and update the function signature to accept a mutable reference with some_string: &mut String . This makes it very clear that the change function will mutate the value it borrows.
Back to Rust. A mutable reference is a borrow to any type mut T , allowing mutation of T through that reference. The below code illustrates the example of a mutable variable and then mutating its value through a mutable reference ref_i .
A reference of a variable is a pointer that leads to that variable. Rust uses the concept of ownership, which is associated with how references are used.
Rust supports a concept, borrowing, where the ownership of a value is transferred temporarily to an entity and then returned to the original owner entity.
Your program panics because you're trying to borrow the Vec
mutably and immutably at the same time: this is not allowed.
What you need to do instead is wrap only the String
s in RefCell
. This allows you to mutate the strings while iterating the Vec
.
use std::cell::RefCell;
struct Res {
name: RefCell<String>,
}
impl Res {
fn new(name: &str) -> Res {
Res {
name: RefCell::new(name.to_string()),
}
}
// I don't need all_res to be mutable
fn normalize(&self, all_res: &Vec<Res>) {
// [...] Iterate through all_res and update self.name
*self.name.borrow_mut() = "foo".to_string();
}
}
fn main() {
let res = vec![Res::new("res1"), Res::new("res2")];
for r in res.iter() {
r.normalize(&res);
}
println!("{}", *res[0].name.borrow());
}
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