问题概述

值缓存是一种更加广泛的实用行为,我们可能希望在代码中的其他闭包中也使用他们。然而,目前 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解决官方文档中的闭包限制的更多相关文章

  1. swift官方文档中的函数闭包是怎么理解的?

    官方文档中的16页: numbers.map({ (number: Int) -> Int in let result = * number return result }) 不知道这个怎么用, ...

  2. swift官方文档中的switch中case let x where x.hasSuffix("pepper")是什么意思?

    在官方文档中,看到这句.但不明白什么意思. let vegetable = "red pepper" switch vegetable { case "celery&qu ...

  3. 从官方文档中探索MySQL分页的几种方式及分页优化

    概览 相比于Oracle,SQL Server 等数据库,MySQL分页的方式简单得多了,官方自带了分页语法 limit 语句: select * from test_t LIMIT {[offset ...

  4. tensorflow官方文档中的sub 和mul中的函数已经在API中改名了

    在照着tensorflow 官方文档和极客学院中tensorflow中文文档学习tensorflow时,遇到下面的两个问题: 1)AttributeError: module 'tensorflow' ...

  5. 【采坑小计】thanos receiver的官方文档中,并未说明tsdb落盘的配置方式

    官方文档的地址在:https://thanos.io/tip/components/receive.md/ 一开始以为落盘的时间间隔是:--tsdb.retention=15d 实际测试中发现,tha ...

  6. 【原创+译文】官方文档中声明的如何创建抽屉导航栏(Navigation Drawer)

    如需转载请注明出处:http://www.cnblogs.com/ghylzwsb/p/5831759.html 创建一个抽屉导航栏 抽屉式导航栏是显示在屏幕的左边缘,它是应用程序的主导航选项面板.它 ...

  7. Django1.7官方文档中的tutorial——翻译

    写下你的第一个Django应用,第一部分 让我们通过例子来学习. 通过这篇指南,我们将会带你浏览一遍一个基本投票应用的创建. 它由两部分组成: 1一个让人们查看投票和进行投票的公共站点 2一个让你添加 ...

  8. Vue官方文档中的camelCased (驼峰式) 命名与 kebab-case

    因为html特性中 元素的 prop是不区分大小写的 所以不管html中怎么大写小写变化,下面的组件的prop应该写成小写 Vue中有这样一种设定: props中如果使用为kebab-case命名方式 ...

  9. 摘录ECMAScript官方文档中重要的两段话

    Every object created by a constructor has an implicit reference (called the object’s prototype) to t ...

随机推荐

  1. GC和GC Tuning

    GC和GC Tuning GC的基础知识 什么是垃圾 C语言申请内存:malloc free C++: new delete c/C++ 手动回收内存 Java: new ? 自动内存回收,编程上简单 ...

  2. uniapp-npm install 进入版本后 优先运行全局安装,在HBuilder X终端输入 npm install 点击回车

    uniapp-npm  install 进入版本后 优先运行全局安装,在HBuilder X终端输入 npm  install 点击回车

  3. css边距重叠的解决方案

    ** css防止边距重叠的方法 ** 今天整理了一下用css防止边距重叠的几种方法先假设一组dom结构 <div class="parent"> <div cla ...

  4. mixin和composition api

    1. 这两个都是实现组件逻辑复用的法宝 2. composition api是vue3的,  composition api的出现就是解决mixins的不足之处的 一. mixin 回顾下mixin, ...

  5. 没有高度的div中的子元素高度自动撑开

     直接上代码: 很多时候 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q ...

  6. Java报错:Unable to find setter method for attribute: [x]

    在学习JavaWeb JSTL与自定义标签时遇到的坑,用的老师给的代码结果直接原地报错:javax.servlet.ServletException: org.apache.jasper.Jasper ...

  7. Python入门-import导入模块功能

    1.啥是模块 模块(module):用来实现或者多个功能的Python代码,(包含变量.函数.类),本质就是*.py后缀文件. 包(package):定义了一个由模块和子包组成的Python应用程序执 ...

  8. php实验一专属跳转博文

    今天完成了php关于设计个人博客主页的实验一作业. 这是php实验一作业中博客的跳转链接页.  

  9. Java学习day5

    API即应用程序编程接口,Java所包含的方法以及类很多,如果要使用他们就得了解这些的API如何使用,因为API多而复杂,我们可以通过帮助文档查询 与c/c++类似,Java通过Scanner类就可以 ...

  10. mysql的半同步复制

    1. binlog dump线程何时向从库发送binlog mysql在server层进行了组提交之后,为了提高并行度,将提交阶段分为了 flush sync commit三个阶段,根据sync_bi ...