【问题标题】:Why does inserting a value into a HashMap always result in the value being None?为什么向 HashMap 中插入值总是导致值为 None?
【发布时间】:2020-12-01 17:20:03
【问题描述】:

我正在尝试创建一个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);
}
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 回调被调用,然后我抛出一个错误。我做错了什么?

【问题讨论】:

  • 顺便说一句,.unwrap_or_else(|| panic!("Unexpected error occurred");) 的惯用方式是 .expect("Unexpected error occurred")

标签: types rust hashmap


【解决方案1】:

您的错误来自以下事实: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()
}

【讨论】:

  • 好的,现在我看到了 If the map did not have this key present, None is returned. 如果我的地图中没有此值,它将始终返回 None,正如您在回答中提到的那样。感谢您的帮助。
  • 你能给我推荐任何资源吗?我可以在其中阅读如何使用 lambda 中使用的self 解决此类问题?目前,我正在阅读The Rust Programming Language
  • Rust Book(你目前正在阅读的)可能是学习 Rust 的最佳资源。您也可以尝试阅读Rust by Example
  • 所以我应该回到Understanding Ownership 再读一遍这一章。谢谢你的建议
猜你喜欢
  • 1970-01-01
  • 2021-03-10
  • 2012-12-26
  • 2021-10-08
  • 1970-01-01
  • 2012-04-04
  • 2022-01-22
  • 1970-01-01
  • 2015-07-14
相关资源
最近更新 更多