I am following "the book" and I'm working on chapter 13 regarding functional programming features. In this chapter I created a Cacher for an expensive function but am stuck with making improvements to fix the limitations mentioned here.
I successfully converted my Cacher to accept generic values but when I want to create the specific case mentioned I cannot. I want to accept a string slice and return usize however, the compiler tells me I can't do this because I am forcing my parameters to have the Copy
trait of which String does not.
How should I have written my Cacher to accept generic functions and allow me pass in 2 different closures. One that simply accepts and returns the u32 parameter passed in and another that accepts a string slice parameter and return usize. I saw an example where the person implemented lifetimes but the code look very unreadable and when I got it to work this way without lifetimes I was happy but maybe that is required. Here is that code found in a SO question.
Here is the relevant code:
edit: I'm unsure why my code is not indented correctly at first. I used the blockquote function. Is this incorrect?
struct Cacher <T, K, V>
where T: Fn(K) -> V
{
calculation: T,
values: HashMap<K, V>,
}
impl<T, K, V> Cacher<T, K, V>
where
T: Fn(K) -> V,
K: Hash + Eq + Clone + Copy,
V: Copy
{
fn new(calculation: T) -> Cacher<T, K, V> {
Cacher {
calculation,
values: HashMap::new()
}
}
fn value(&mut self, arg: K) -> V {
match self.values.get(&arg) {
Some(v) => *v,
None => {
let v = (self.calculation)(arg);
self.values.insert(arg, v);
v
},
}
}
}
Here are the 2 closures I'm trying to implement:
let mut expensive_closure = Cacher::new(|num| {
println!("calculating slowly...");
thread::sleep(Duration::from_secs(2));
num
});
let mut expensive_closure_2 = Cacher::new(|string_slice: String| {
println!("calculating slowly...");
thread::sleep(Duration::from_secs(2));
string_slice.chars().count()
});