Generic Cache struct I've came up with the following implementation of a very simple cache:

use std::cmp::Eq;
use std::collections::HashMap;
use std::hash::Hash;

pub struct Cache&lt;I, R, F&gt;
    where I: Copy + Eq + Hash, F: Fn(I) -&gt; R
{
    calculation: F,
    values: HashMap&lt;I, R&gt;,
}

impl&lt;I, R, F&gt; Cache&lt;I, R, F&gt; where I: Copy + Eq + Hash, F: Fn(I) -&gt; R {
    pub fn new(calculation: F) -&gt; Cache&lt;I, R, F&gt; {
        Cache { calculation, values: HashMap::new() }
    }
    pub fn value(&amp;mut self, arg: I) -&gt; &amp;R {
        // Pop or calculate new value
        let result = match self.values.remove(&amp;arg) {
            Some(v) =&gt; v,
            None =&gt; (self.calculation)(arg)
        };
        // Store value
        self.values.insert(arg, result);
        // Return a reference to it
        self.values.get(&amp;arg).unwrap()
    }
}


A simple usage example would be:

fn to_lowercase(value: &amp;str) -&gt; String {
    println!("Calculating \"{}\".to_lowercase()", value);
    value.to_lowercase()
}

fn main() {
    let mut cache = Cache::new(to_lowercase);
    println!("Calculated: {}", cache.value("ABC"));
    println!("Calculated: {}", cache.value("ABC"));
}


Which prints:

Calculating "ABC".to_lowercase()
Calculated: abc
Calculated: abc


However, I feel like my code is much more complicated than it needs to be (specially around the Cache.value implementation), what can be improved here?
The biggest change you can do is to the value function. Because most of what you are building is actually provided via HashMap'sentry API. This could reduce the body of your value function to simply this:

match self.values.entry(arg) {
    Entry::Occupied(val) =&gt; val.into_mut(),
    Entry::Vacant(slot) =&gt; slot.insert((self.calculation)(arg)),
}


You could also mess with Entry's or_insert_with function, but I personally prefer the approach above.

You may also consider using Clone instead of Copy. The advantage of Clone are that it is more explicit and that it should support more types. The disadvantage obviously is that clone can be arbitrarily expensive. In general I'd say you want Clone for a generic interface such as this.

Finally, I understand it's an exercise, but the names are a bit plain:


Cache is very generic: what do you actually cache? Call it something like FunctionResultCache or Memoizer
value is also a bit weird. What you're doing in essence is wrapping a function, so I'd name this call or invoke or something similar.