2

I boiled my code down to these lines:

#[derive(Debug)]
struct Config {
    values: Vec<String>,
    compiled: Option<Vec<String>>,
}

impl Config {
    fn comp_values(&mut self) -> &Vec<String> {
        if self.compiled.is_none() {
            self.compiled = Some(self.values.clone());
        }
        self.compiled.as_ref().unwrap()
    }

    fn comp_values_match(&mut self) -> &Vec<String> {
        match self.compiled {
            Some(_) => self.compiled.as_ref().unwrap(),
            None => {
                self.compiled = Some(self.values.clone());
                self.compiled.as_ref().unwrap()
            }
        }
    }
}

fn main() {
    let mut c = Config {
        values: vec![String::from("a"), String::from("b")],
        compiled: None,
    };
    println!("config before: {:?}", c);
    println!("compiled: {:?}", c.comp_values());
    println!("config after: {:?}", c);
}

What I would like to have is something like:

match self.compiled {
    Some(v) => v,
    None => {
        // assemble v and assign it to self.compiled
        v
    },
}

just like in the closure chapter in the book. Is it possible in the book it only worked, because u32 implements the Copy trait? If I change the match line to match self.compiled.as_ref() the Some(v) => v, works. In the None arm I then can't assign like self.compiled = ... since I have have the variable 'open' (or referenced with self.compiled.as_ref()) in that block.

Are my assumptions correct? Is the comp_values() method the most elegant solution in that case?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • [The duplicate applied to your situation](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=996a256c8a627e24079c634dbf20c94a) – Shepmaster Apr 14 '20 at 17:47
  • [Why is it discouraged to accept a reference to a String (&String), Vec (&Vec), or Box (&Box) as a function argument?](https://stackoverflow.com/q/40006219/155423) – Shepmaster Apr 14 '20 at 17:48
  • 1
    @Shepmaster thanks for the hint with &[...] With your code: the `Self {...} = self` you are basically deconstructing the struct and create new local variables which are references, right? But why isn't `self.compiled.get_or_insert_with(|| self.values.clone())` not working? Is it because with your solution I get multiple `&mut` idependent from each other and with my solution one reference within anoghter? Sorry my bad english... – Richard Pöttler Apr 14 '20 at 19:21
  • That's absolutely correct. The closure captures `self` and the compiler effectively doesn't know what you will do with it at that point, so it can't guarantee that it's safe. Borrowing the fields beforehand make it very clear that they don't overlap. See also [Mutably borrow one struct field while borrowing another in a closure](https://stackoverflow.com/q/36379242/155423) (Your English is fine!) – Shepmaster Apr 14 '20 at 19:39

1 Answers1

1

Not a match statement, but I think you are looking for get_or_insert_with.

phimuemue
  • 34,669
  • 9
  • 84
  • 115