对非结构体方法的函数实现缓存的惯用方法是什么?

问题描述 投票:0回答:2

我有一个像这样昂贵的功能:

pub fn get_expensive_value(n: u64): u64 {
   let ret = 0;
   for 0 .. n {
       // expensive stuff
   }
   ret
}

并且它经常被使用相同的参数调用。它是纯粹的,所以这意味着它将返回相同的结果并且可以利用缓存。

如果这是一个结构体方法,我会向该结构体添加一个充当缓存的成员,但事实并非如此。所以我的选择似乎是使用静态:

static mut LAST_VAL: Option<(u64, u64)> = None;

pub fn cached_expensive(n: u64) -> u64 {
   unsafe {
       LAST_VAL = LAST_VAL.and_then(|(k, v)| {
           if k == n {
              Some((n,v))
           } else {
              None
           }
       }).or_else(|| {
           Some((n, get_expensive_value(n)))
       });
       let (_, v) = LAST_VAL.unwrap();
       v
   }
}

现在,我不得不使用

unsafe
。我可以使用
static mut
代替
RefCell
,但我不相信这更安全 - 它只是避免使用
unsafe
块。我考虑过
Mutex
,但我认为这也不能让我获得线程安全。

重新设计代码以使用结构体进行存储并不是一个真正的选择。

caching rust static-members
2个回答
8
投票

我认为最好的选择是使用带有互斥锁的全局变量。使用lazy_static使其变得简单并允许在函数内进行“全局”声明

pub fn cached_expensive(n: u64) -> u64 {
    use std::sync::Mutex;
    lazy_static! {
        static ref LAST_VAL: Mutex<Option<(u64, u64)>> = Mutex::new(None);
    }
    let mut last = LAST_VAL.lock().unwrap();
    let r = last.and_then(|(k, v)| {
        if k == n {
            Some((n, v))
        } else {
            None
        }
    }).or_else(|| Some((n, get_expensive_value(n))));
    let (_, v) = r.unwrap();
    *last = r;
    v
}

7
投票

您还可以查看 cached 项目/板条箱。它用一个简单的宏来记忆该函数。

© www.soinside.com 2019 - 2024. All rights reserved.