Updating Cache Struct via Mutable Reference
Problem Description:
I have this simple struct called Path
:
struct Path {
path_string: String,
path_vec: Option<Vec<String>>,
}
The String
is a path where each piece is separated by "/"
and the vector representation is simply a list of the pieces. I wanted to be able to be able to cache the vector field on the first time it is accessed hence the Option
wrapper.
I have the following function to access the vector:
fn as_vec<'path>(&'path mut self) -> &'path Vec<String> {
if self.path_vec.is_none() {
let xs: Vec<String> = self.path_string.split("/").map(|s| s.to_string()).collect();
self.path_vec = Some(xs);
}
match &self.path_vec {
Some(xs) => xs,
None => panic!("The impossible happened!"),
}
}
Is there a nicer way to structure this function that avoids the panic
?
I originally tried to write something like this:
fn as_vec<'path>(&'path mut self) -> &'path Vec<String> {
match &self.path_vec {
Some(xs) => xs,
None => {
let xs: Vec<String> = self.path_string.split("/").map(|s| s.to_string()).collect();
self.path_vec = Some(xs);
self.as_vec()
}
}
}
But the self.path_vec = Some(xs);
doesn’t work because it isn’t possible to update the struct when it’s borrowed in the match.
Updating the match to use a mutable reference also doesn’t work because it’s not possible to have more than one mutable reference at a time.
Is this something that can be worked around or am I just stuck with the panic
?
Solution – 1
Use Option::get_or_insert_with()
:
fn as_vec<'path>(&'path mut self) -> &'path Vec<String> {
self.path_vec
.get_or_insert_with(|| self.path_string.split("/").map(|s| s.to_string()).collect())
}