Reputation: 135
I am following the introductory book. In section 13.1, the authors implemented a "Cacher" and asked the reader to implement it with a HashMap
. I have gotten it to work, but I'm not quite content because of a call to unwrap()
which seems a bit out of place.
Specifically, in the Cacher::value()
, the Some(v) => v.unwrap()
call is what displeases me - considering the documentation of unwrap()
states that calls to the function should be avoided. What is a better/more idiomatic suggestion for doing what I'm trying to accomplish?
The code:
use std::collections::HashMap;
struct Cacher<T> {
calculation: T,
hmap: HashMap<u32, Option<u32>>,
}
impl<T> Cacher<T>
where
T: Fn(u32) -> u32,
{
fn new(calculation: T) -> Cacher<T> {
Cacher {
calculation,
hmap: HashMap::new(),
}
}
fn value(&mut self, arg: u32) -> u32 {
match self.hmap.get(&arg) {
Some(v) => v.unwrap(),
None => {
let v = (self.calculation)(arg);
self.hmap.insert(arg, Some(v));
v
}
}
}
}
fn main() {
let mut cache = Cacher::new(|x| x * x);
let v = vec![cache.value(1), cache.value(2), cache.value(3)];
println!("v: {:?}", v);
}
Upvotes: 2
Views: 630
Reputation: 135
There is no need to have an Option
in the HashMap<u32, Option<u32>>
because the HashMap
itself may represent whether a value is cached or not. The new and improved code:
use std::collections::HashMap;
struct Cacher<T> {
calculation: T,
hmap: HashMap<u32, u32>,
}
impl<T> Cacher<T>
where
T: Fn(u32) -> u32,
{
fn new(calculation: T) -> Cacher<T> {
Cacher {
calculation,
hmap: HashMap::new(),
}
}
fn value(&mut self, arg: u32) -> u32 {
match self.hmap.get(&arg) {
Some(v) => *v,
None => {
let v = (self.calculation)(arg);
self.hmap.insert(arg, v);
v
}
}
}
}
fn main() {
let mut cache = Cacher::new(|x| x * x);
let v = vec![cache.value(1), cache.value(2), cache.value(3)];
println!("v: {:?}", v);
}
Upvotes: 2