【Rust】使用HashMap解決官方文件中的閉包限制

HoseaCube發表於2022-05-14

問題概述

值快取是一種更加廣泛的實用行為,我們可能希望在程式碼中的其他閉包中也使用他們。然而,目前 Cacher 的實現存在兩個小問題,這使得在不同上下文中複用變得很困難。

第一個問題是 Cacher 例項假設對於 value 方法的任何 arg 引數值總是會返回相同的值。也就是說,這個 Cacher 的測試會失敗:

《rust程式設計語言》13章閉包內容提出的問題
 #[test]
    fn call_with_different_values() {
        let mut c = Cacher::new(|a| a);

        let v1 = c.value(1);
        let v2 = c.value(2);

        assert_eq!(v2, 2);
    }

具體程式碼請在《rust程式設計語言》第13章第一節 Cacher 實現的限制 中找到。


解決思路

嘗試修改 Cacher 存放一個雜湊 map 而不是單獨一個值。雜湊 map 的 key 將是傳遞進來的 arg 值,而 value 則是對應 key 呼叫閉包的結果值。

相比之前檢查 self.value 直接是 Some 還是 None 值,現在 value 函式會在雜湊 map 中尋找 arg,如果找到的話就返回其對應的值。如果不存在,Cacher 會呼叫閉包並將結果值儲存在雜湊 map 對應 arg 值的位置。

《rust程式設計語言》13章閉包內容提出的解決思路

解決方案

更改Cacher結構體的型別

use std::collections::HashMap;
struct Cacher<T>
where
    T: Fn(u32) -> u32,
{
    calculation: T,
    value: HashMap<u32, u32>,
}

將之前儲存單一u32型別的 value欄位 替換成 HashMap型別,此HashMap的key和value都為u32型別

更改chacher結構體的方法

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

    fn value(&mut self, arg: u32) -> u32 {
        match self.value.get(&arg) {
            Some(v) => *v,
            None => {
                let v = (self.calculation)(arg);
                self.value.insert(arg, v);
                arg
            }
        }
    }
}

new方法中返回的Cacher例項,value欄位 不再為Option<u32>型別,取而代之的是一個 被初始化的HashMap,用於存放 不同引數的結果快取

value方法中,不再直接匹配結構體的value欄位,而是通過 引數 去value欄位的 HashMap 中找到儲存的值並返回,要是找不到則在HashMap中插入 key值為傳入引數value值為結構體閉包呼叫引數所得的結果。


測試結果

fn main() {
    let mut cal = Cacher::new(|num| {
        println!("calculating slowly...");
        thread::sleep(Duration::from_secs(2));
        num
    });

    println!("{}", cal.value(1));
    println!("{}", cal.value(2));
    println!("{}", cal.value(1))
}
cargo run
   Compiling closure v0.1.0 (D:\project\rust\closure)
    Finished dev [unoptimized + debuginfo] target(s) in 0.66s
     Running `target\debug\closure.exe`
calculating slowly...
1
calculating slowly...
2
1

測試通過

相關文章