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 )
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