Updating Cache Struct via Mutable Reference

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())
}
Rate this post
We use cookies in order to give you the best possible experience on our website. By continuing to use this site, you agree to our use of cookies.
Accept
Reject