如何利用Rust的HashMap克服官方文档中闭包的约束?

2026-05-06 02:511阅读0评论SEO教程
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计695个文字,预计阅读时间需要3分钟。

如何利用Rust的HashMap克服官方文档中闭包的约束?

问题概述:值缓存是一种增加泛用性的实用行为,我们可能希望在其他代码中的其他闭包中也能使用它们。然而,目前Cacher的实现存在两个小问题,这使得在不同上下文中复用变得非常困难。

问题一:Cacher的实现细节不明确,导致在不同上下文中难以复用。

问题概述

值缓存是一种更加广泛的实用行为,我们可能希望在代码中的其他闭包中也使用他们。然而,目前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值为结构体闭包调用参数所得的结果。

如何利用Rust的HashMap克服官方文档中闭包的约束?


测试结果

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

测试通过

本文共计695个文字,预计阅读时间需要3分钟。

如何利用Rust的HashMap克服官方文档中闭包的约束?

问题概述:值缓存是一种增加泛用性的实用行为,我们可能希望在其他代码中的其他闭包中也能使用它们。然而,目前Cacher的实现存在两个小问题,这使得在不同上下文中复用变得非常困难。

问题一:Cacher的实现细节不明确,导致在不同上下文中难以复用。

问题概述

值缓存是一种更加广泛的实用行为,我们可能希望在代码中的其他闭包中也使用他们。然而,目前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值为结构体闭包调用参数所得的结果。

如何利用Rust的HashMap克服官方文档中闭包的约束?


测试结果

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

测试通过