【Rust】使用HashMap解决官方文档中的闭包限制
问题概述
值缓存是一种更加广泛的实用行为,我们可能希望在代码中的其他闭包中也使用他们。然而,目前 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测试通过
【Rust】使用HashMap解决官方文档中的闭包限制的更多相关文章
- swift官方文档中的函数闭包是怎么理解的?
		官方文档中的16页: numbers.map({ (number: Int) -> Int in let result = * number return result }) 不知道这个怎么用, ... 
- swift官方文档中的switch中case let x where x.hasSuffix("pepper")是什么意思?
		在官方文档中,看到这句.但不明白什么意思. let vegetable = "red pepper" switch vegetable { case "celery&qu ... 
- 从官方文档中探索MySQL分页的几种方式及分页优化
		概览 相比于Oracle,SQL Server 等数据库,MySQL分页的方式简单得多了,官方自带了分页语法 limit 语句: select * from test_t LIMIT {[offset ... 
- tensorflow官方文档中的sub 和mul中的函数已经在API中改名了
		在照着tensorflow 官方文档和极客学院中tensorflow中文文档学习tensorflow时,遇到下面的两个问题: 1)AttributeError: module 'tensorflow' ... 
- 【采坑小计】thanos receiver的官方文档中,并未说明tsdb落盘的配置方式
		官方文档的地址在:https://thanos.io/tip/components/receive.md/ 一开始以为落盘的时间间隔是:--tsdb.retention=15d 实际测试中发现,tha ... 
- 【原创+译文】官方文档中声明的如何创建抽屉导航栏(Navigation Drawer)
		如需转载请注明出处:http://www.cnblogs.com/ghylzwsb/p/5831759.html 创建一个抽屉导航栏 抽屉式导航栏是显示在屏幕的左边缘,它是应用程序的主导航选项面板.它 ... 
- Django1.7官方文档中的tutorial——翻译
		写下你的第一个Django应用,第一部分 让我们通过例子来学习. 通过这篇指南,我们将会带你浏览一遍一个基本投票应用的创建. 它由两部分组成: 1一个让人们查看投票和进行投票的公共站点 2一个让你添加 ... 
- Vue官方文档中的camelCased (驼峰式) 命名与 kebab-case
		因为html特性中 元素的 prop是不区分大小写的 所以不管html中怎么大写小写变化,下面的组件的prop应该写成小写 Vue中有这样一种设定: props中如果使用为kebab-case命名方式 ... 
- 摘录ECMAScript官方文档中重要的两段话
		Every object created by a constructor has an implicit reference (called the object’s prototype) to t ... 
随机推荐
- GC和GC Tuning
			GC和GC Tuning GC的基础知识 什么是垃圾 C语言申请内存:malloc free C++: new delete c/C++ 手动回收内存 Java: new ? 自动内存回收,编程上简单 ... 
- uniapp-npm  install 进入版本后 优先运行全局安装,在HBuilder X终端输入 npm  install 点击回车
			uniapp-npm install 进入版本后 优先运行全局安装,在HBuilder X终端输入 npm install 点击回车 
- css边距重叠的解决方案
			** css防止边距重叠的方法 ** 今天整理了一下用css防止边距重叠的几种方法先假设一组dom结构 <div class="parent"> <div cla ... 
- mixin和composition api
			1. 这两个都是实现组件逻辑复用的法宝 2. composition api是vue3的, composition api的出现就是解决mixins的不足之处的 一. mixin 回顾下mixin, ... 
- 没有高度的div中的子元素高度自动撑开
			直接上代码: 很多时候 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q ... 
- Java报错:Unable to find setter method for attribute: [x]
			在学习JavaWeb JSTL与自定义标签时遇到的坑,用的老师给的代码结果直接原地报错:javax.servlet.ServletException: org.apache.jasper.Jasper ... 
- Python入门-import导入模块功能
			1.啥是模块 模块(module):用来实现或者多个功能的Python代码,(包含变量.函数.类),本质就是*.py后缀文件. 包(package):定义了一个由模块和子包组成的Python应用程序执 ... 
- php实验一专属跳转博文
			今天完成了php关于设计个人博客主页的实验一作业. 这是php实验一作业中博客的跳转链接页. 
- Java学习day5
			API即应用程序编程接口,Java所包含的方法以及类很多,如果要使用他们就得了解这些的API如何使用,因为API多而复杂,我们可以通过帮助文档查询 与c/c++类似,Java通过Scanner类就可以 ... 
- mysql的半同步复制
			1. binlog dump线程何时向从库发送binlog mysql在server层进行了组提交之后,为了提高并行度,将提交阶段分为了 flush sync commit三个阶段,根据sync_bi ... 
