magnusmaehlum
magnusmaehlum

Reputation: 135

How do I avoid unwrapping an Option returned from accessing a HashMap with an Option as the value?

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

Answers (1)

magnusmaehlum
magnusmaehlum

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

Related Questions