为什么向 HashMap 插入一个值总是会导致该值为 None?

Kan*_*now 0 types hashmap rust

我正在尝试创建一个Cacher结构,它将计算值存储在HashMap. 该calculation方法将采用一个类型的变量T,进行计算并返回一个具有相同类型的值T。此回调的类型calculation将为Fn(T) -> T.

我发现这个值将是HashMap实现EqHash特征的关键。看起来一切都应该正常,我可以毫无错误地编译我的程序。

然后我编写了一个测试来检查一切是否按预期工作:

use std::{hash::Hash, collections::HashMap};

struct Cacher<T, U>
where
    T: Fn(U) -> U,
{
    calculation: T,
    values: HashMap<U, U>,
}

impl<T, U> Cacher<T, U>
where
    T: Fn(U) -> U,
    U: Eq + Hash + Clone,
{
    fn new(calculation: T) -> Cacher<T, U> {
        return Cacher {
            calculation,
            values: HashMap::new(),
        };
    }

    fn value(&mut self, arg: U) -> U {
        let result = self.values.get(&arg);
        return match result {
            Some(v) => v.clone(),
            None => self
                .values
                .insert(arg.clone(), (self.calculation)(arg.clone()))
                .unwrap_or_else(|| {
                    panic!("Unexpected error occurred");
                })
                .clone(),
        };
    }
}

#[test]
fn call_with_different_values() {
    let mut c = Cacher::new(|a: i32| a);
    let v1 = c.value(1);
    let v2 = c.value(2);
    assert_eq!(v2, 2);
}
Run Code Online (Sandbox Code Playgroud)
thread 'call_with_different_values' panicked at 'Unexpected error occurred', src/lib.rs:31:21
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Run Code Online (Sandbox Code Playgroud)

当我将新值插入到 my 中时HashMap,它总是以 结束Option::Noneunwrap_or_else调用我的回调,然后抛出错误。我究竟做错了什么?

Apl*_*123 5

您的错误来自这样一个事实:insert返回一个Option带有键上的前一个值的值,而不是新值。相反,使用Entry

fn value(&mut self, arg: U) -> U {
    // ugly workaround to borrow checker complaining when writing these inline
    let value_ref = &mut self.values;
    let calculation_ref = &self.calculation;
    let result = value_ref.get(&arg);
    self.values.entry(arg.clone())
        .or_insert_with(|| (calculation_ref)(arg.clone()))
        .clone()
}
Run Code Online (Sandbox Code Playgroud)

  • 《Rust Book》(您当前正在阅读的书)可能是学习 Rust 的最佳来源。您还可以尝试阅读 [*Rust 示例*](https://doc.rust-lang.org/rust-by-example/)。 (2认同)