为什么向 HashMap 中插入一个值总是导致该值是 None?
Why does inserting a value into a HashMap always result in the value being None?
我正在尝试创建一个 Cacher
结构,它将计算值存储在 HashMap
中。 calculation
方法将接受一个类型为 T
的变量,进行计算并 return 一个具有相同类型 T
的值。此 calculation
回调的类型将为 Fn(T) -> T
.
我发现作为 HashMap
键的值必须实现 Eq
和 Hash
特征。看起来一切正常,我可以毫无错误地编译我的程序。
然后我写了一个测试来检查一切是否按预期工作:
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);
}
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
当我向我的 HashMap
中插入一个新值时,它总是以 Option::None
结束,我的 unwrap_or_else
回调被调用,然后我抛出一个错误。我做错了什么?
您的错误是因为 insert
returns 一个 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()
}
我正在尝试创建一个 Cacher
结构,它将计算值存储在 HashMap
中。 calculation
方法将接受一个类型为 T
的变量,进行计算并 return 一个具有相同类型 T
的值。此 calculation
回调的类型将为 Fn(T) -> T
.
我发现作为 HashMap
键的值必须实现 Eq
和 Hash
特征。看起来一切正常,我可以毫无错误地编译我的程序。
然后我写了一个测试来检查一切是否按预期工作:
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);
}
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
当我向我的 HashMap
中插入一个新值时,它总是以 Option::None
结束,我的 unwrap_or_else
回调被调用,然后我抛出一个错误。我做错了什么?
您的错误是因为 insert
returns 一个 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()
}