I have the following code in Rust:
pub struct RegExpFilter {
...
regexp_data: RefCell<Option<RegexpData>>,
...
}
struct RegexpData {
regexp: regex::Regex,
string: String
}
...
pub fn is_regexp_compiled(&self) -> bool {
self.regexp_data.borrow().is_some()
}
pub fn compile_regexp(&self) -> RegexpData {
...
}
fn regexp(&self) -> ®ex::Regex {
if !self.is_regexp_compiled() { // lazy computation that mutates the struct
self.regexp_data.replace(Some(self.compile_regexp()));
}
&self.regexp_data.borrow().as_ref().unwrap().regexp
}
pub fn matches(&self, location: &str) -> bool {
self.regexp().find(location)
}
regexp is calculated lazily, capturing &mut self i undesired so RefCell is used.
I'm getting the following message:
&self.regexp_data.borrow().as_ref().unwrap().regexp
| ^-------------------------^^^^^^^^^^^^^^^^^^^^^^^^^
| ||
| |temporary value created here
| returns a value referencing data owned by the current function
The compiler message seems to be clear: Ref is temporarily created by borrow() and returned outside. However i believe Option (self.regexp_data) is owned by RefCell which is owned by the struct itself, so it should be fine to use it internally (since the function is not pub).
I've also tried the following (and it fails with the same message)
fn regexp(&self) -> impl Deref<Target = regex::Regex> + '_ {
if !self.is_regexp_compiled() {
self.regexp_data.replace(Some(self.compile_regexp()));
}
Ref::map(self.regexp_data.borrow(), |it| &it.unwrap().regexp)
}
How can i solve it?
You can fix the
Ref::mapversion by using.as_ref()to convert the&Option<_>to aOption<&_>in order to to unwrap as a reference:In this scenario, I'd advocate for using
OnceCellfrom the once_cell crate:You can simply use
get_or_initto get the same effect.OnceCellandLazy(in the same crate) are very convenient for lazy-evaluation.See it on the playground.