So I have a sort of a database struct which stores data for my app. When the data is dirty, it fetches it from the database and stores it inside of the struct. Either way, when this data is requested (Vec<&str>
), we will have an existing String
stored somewhere inside the database struct.
To the outside, it should look like this database is not mutating itself, because it should just look like it's just fetching data from the database. However, on the inside, it's actually storing some cache so that it doesn't have to fetch data every frame. So, I use a RefCell<Vec<String>>
to store the cache.
Ok, so now I should be able to just get a Vec<&str>
, where the &str
is referencing that String
that's stored in our database struct.
However, this cache is not guaranteed to always exist. For example, when it's invalidated, and the data needs to be fetched again. So actually, we have a RefCell<Option<Vec<String>>>
:
use std::cell::RefCell;
struct Connection {}
pub struct Database {
db: Connection,
projects_cache: RefCell<Option<Vec<String>>>,
// ...
}
Unfortunately, I can't seem to do this:
impl Database {
pub fn projects(&self) -> Result<Vec<&str>, ()> {
if self.projects_cache.borrow().is_some() {
let cached: &Vec<String> = &*self.projects_cache.borrow().as_ref().unwrap();
return Ok(cached.iter().map(|name| name.as_str()).collect());
}
// if not, then fetch data from the database and store it in the cache
// ...
unimplemented!()
}
}
Apparently this is a temporary value.
error[E0515]: cannot return value referencing temporary value
--> src/lib.rs:15:20
|
14 | let cached: &Vec<String> = &*self.projects_cache.borrow().as_ref().unwrap();
| ---------------------------- temporary value created here
15 | return Ok(cached.iter().map(|name| name.as_str()).collect());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function
So my question is:
Why is this value temporary? The
String
exists. We're just trying to take a reference to it. So why would it be temporary?How do I do this idiomatically? I'm not attached to this method at all. All I care about is that: I can store a cache; the fetch function takes
&self
and appears immutable from the outside; and that I don't have to make a brand new copy ofString
every single frame, for performance reasons.