[Solved] Reference after filling Option

I'm a beginner rustacean: tackled some small puzzles and up-to-speed on the syntax and type rules. Generally OK on lifetimes (in theory), but struggling a bit in practice.

I'm having trouble polishing this lazy evaluation/caching function. Tweaking to make it compile makes it less straightforward to read. Thinking there's got to be a clever way to implement this simple pattern of lazy-compute / caching. (Biggest issue is I don't know what to google for :confused: )

Goal

For a Copy type this is easy to read, and it works! playground #0

/// Playground #0 snippet
struct LazyFoo {
    maybe_val: Option<usize>,
}
impl LazyFoo {
    fn new() -> Self {
        LazyFoo { maybe_val: None }
    }
    fn get(&mut self) -> usize {
        if let Some(val) = self.maybe_val {
            // use cached value
            val
        } else {
            // calculate value, (very expensive)
            let new_val = 2+2;
            // store for later retrieval
            self.maybe_val = Some(new_val);
            new_val
        }
    }
}

My Problem

But for a non-Copy type (Vec, returning as a slice), I'm getting tangled up in lifetimes. failing playground #1

Reworking the if let Some(..) logic, I can manage to get it to compile. ugly, but working playground #2

/// Playground #2 snippet
struct LazyFoo {
    maybe_val: Option<Vec<usize>>,
}
impl LazyFoo {
    fn new() -> Self {
        LazyFoo { maybe_val: None }
    }
    fn get(&mut self) -> &Vec<usize> {
        if let None = &self.maybe_val {
            // calculate val, (very expensive)
            let new_val = vec![2+2];
            // store for later retrieval
            self.maybe_val = Some(new_val);
            // want to do this: return &new_val;
        }
        // instead, stuck checking again with "edge case" that will never happen
        if let Some(val) = &self.maybe_val {
            return val;
        }
        unreachable!(); // UGLY
    }
}

I really don't like the duplicate if let None then if let Some checks.
From what I understand, unreachable!() is a last resort. It just looks tacky.
There's got to be a better way.

All help or suggestions are welcome :slight_smile:

I think you want Option::get_or_insert_with.

1 Like

Option is filled with lots of useful functions for almost everything. It's well worth the investment to read through all the methods that it has.

Thanks @cuviper, you hit the nail on the head!

I recall finding other specific-yet-useful methods in Option earlier, just hadn't come across this one yet.
Thanks for the suggestion @RustyYato, I'll make sure to read the full docs page.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.