How to mutate a struct Option<value>?

Here is my struct:

    pub struct Scanner<'a> {
        filepath: String,
        header: Option<&'a Header>,
        field_counters: Option<Counters>,
    }

Here is a function that is part of the implementation. It is this function that everything seems to hinge.

        pub fn run(&mut self) -> Option<&'a Counters> {
            if let Some(mut counters) = self.field_counters.take() {
                count_field_in_file(&self.filepath, &mut counters).ok()
            } else {
                None
            }
        }

It utilizes a function that takes and returns a &mut (effectively anyway).

    pub fn count_field_in_file<'a>(
        filepath: &str,
        counters: &'a mut Counters,
    ) -> Result<&'a Counters, Box<dyn Error>> { /* go do it */}

With this latest iteration of the run function, because I transfer ownership to the function, I then get caught with "returns a value referencing data owned by the current function". I get the error... perfect sense. What I don't get, is how to think differently about how to get the pieces of this puzzle to fit.

I believe the challenge is how to access the value both to share a &mut to update the value... it's like a mutate in place except that I'm dealing with two different enums! I could change the struct to accomodate the situation...

Any ideas would be greatly appreciated.

- E

Something needs to continue to own the Counters data after run is called. Some options are to:

  • Make count_field_in_file take and return Counters and not &mut Counters
pub fn count_field_in_file<'a>(filepath: &'a str, counters: mut Counters) 
    -> Result<Counters, Box<dyn Error>>
{ 
    todo!()
}
  • Make run return Option<Counters>
pub fn run(&mut self) -> Option<Counters> {
    let mut counters = self.field_counters.take()?;
    let _ = count_field_in_file(&self.filepath, &mut counters).ok()?;
    Some(counters)
}
  • Continue to store the counters in self after the call to field_counters_take:
pub fn run(&'a mut self) -> Option<&'a Counters> {
    match self.field_counters {
        Some(ref mut counters) => count_field_in_file(&self.filepath, counters).ok(),
        None => None,
    }
}
1 Like

Wonderful. The last one was more of my original intent. All three demonstrated a comprehensive solution and way to think through it. Thank you! - E

Another way to write the last version is:

fn run(&mut self) -> Option<&Counters> {
    count_field_in_file(
        &self.filepath,
        self.field_counters.as_mut()?
    ).ok()
}
2 Likes