use std::{thread, time::Duration, collections::HashMap}; fn main() { let simulated_user_specified_value = 10; let simulated_random_value = 7; generate_workout(simulated_user_specified_value, simulated_random_value); } struct Cacher where T: Fn(u32) -> u32, { calculation: T, value: Option>, } impl Cacher where T: Fn(u32) -> u32, { /** * Cacher 结构体的字段是私有的,因为我们希望cacher管理这些值而不是 * 任由调用代码有着潜在地直接改变他们。 */ fn new(calculation: T) -> Cacher { Cacher { calculation, value: None, } } fn value(&mut self, arg: u32) -> u32 { match &mut self.value { Some(map) => { match map.get(&arg) { Some(v) => v.clone(), None => { let v = (self.calculation)(arg); map.insert(arg, v); v }, } }, None => { let v = (self.calculation)(arg); let mut hash: HashMap = HashMap::new(); hash.insert(arg, v); assert_eq!(hash.is_empty(), false); self.value = Some(hash); v } } } } /** * 希望能够在程序的一个位置指定某些代码 * 并只在程序的某处实际需要结果的时候 执行 这些代码 */ fn generate_workout(intensity: u32, random_number: u32) { let mut expensive_result = Cacher::new(|num| { println!("calculating slowly..."); thread::sleep(Duration::from_secs(2)); num }); if intensity < 25 { println!("Today, do {} pushups!", expensive_result.value(intensity)); println!("Next, do {} situps!", expensive_result.value(intensity + 3)); } else { if random_number == 3 { println!("Take a break today! Remember to stay hydrated!"); } else { println!( "Today, run for {} minutes!", expensive_result.value(intensity) ); } } } // fn simulated_expensive_calculation(intensity: u32) -> u32 { // println!("calculating slowly..."); // thread::sleep(Duration::from_secs(2)); // intensity // } #[cfg(test)] mod tests { use super::*; #[test] fn call_with_different_values() { let mut c = Cacher::new(|a| a); let v1 = c.value(1); println!("v1 {}", v1); let v2 = c.value(2); println!("v2 {}", v2); assert_eq!(v2, 2); } }