gaols
gaols

Reputation: 361

how to fix 'creates a temporary which is freed while still in use'?

I'm learning Rust and trying to implement a cache-like struct to cache an object, but I'm stuck on an error.

src/main.rs

// The Result object to be cached
struct Result {
    value: u32,
}

struct Cacher<'a, T>
where
    T: Fn(u32) -> u32,
{
    calc: T,
    value: Option<&'a Result>,
}

impl<'a, T> Cacher<'a, T>
where
    T: Fn(u32) -> u32,
{
    fn new(calc: T) -> Cacher<'a, T> {
        Cacher { calc, value: None }
    }

    fn get_value(&mut self, arg: u32) -> &Result {
        match self.value {
            Some(v) => v,
            None => {
                let v = (self.calc)(arg);
                self.value = Some(&Result { value: v });
                self.value.unwrap()
            }
        }
    }
}

This results in the following error:

error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:28:40
   |
15 |     impl<'a, T> Cacher<'a, T>
   |          -- lifetime `'a` defined here
...
28 |                     self.value = Some(&Result { value: v });
   |                     -------------------^^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
   |                     |                  |
   |                     |                  creates a temporary which is freed while still in use
   |                     assignment requires that borrow lasts for `'a`

How would one fix this?

Upvotes: 3

Views: 4935

Answers (1)

Dmitry
Dmitry

Reputation: 1637

You cannot return a reference to a value if no one owns this value. Also when you are using your Cacher you need to ensure that reference you've got by get_value will not outlive Cacher itself.

// The Result object to be cached
struct Result {
    value: u32,
}

struct Cacher<T>
where
    T: Fn(u32) -> u32,
{
    calc: T,
    value: Option<Result>, // We need to own the Result
}

impl<T> Cacher<T>
where
    T: Fn(u32) -> u32,
{
    fn new(calc: T) -> Cacher<T> {
        Cacher { calc, value: None }
    }

    fn get_value(&mut self, arg: u32) -> &Result {
        match self.value {
            Some(ref v) => v, // destructuring value by reference to it
            None => {
                let v = (self.calc)(arg);
                self.value = Some(Result { value: v });
                self.value.as_ref().unwrap() // unwrapping value by reference to it
            }
        }
    }
}

Upvotes: 2

Related Questions