在不是结构方法的函数上实现缓存的惯用方法是什么?
What is the idiomatic way to implement caching on a function that is not a struct method?
我有这样一个昂贵的功能:
pub fn get_expensive_value(n: u64): u64 {
let ret = 0;
for 0 .. n {
// expensive stuff
}
ret
}
并且它被频繁地使用相同的参数调用。它是纯粹的,所以这意味着它将 return 相同的结果并且可以使用缓存。
如果这是一个结构方法,我会在结构中添加一个成员作为缓存,但事实并非如此。所以我的选择似乎是使用静态:
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
。我可以将 RefCell
放在 const
中,而不是 static mut
。但我不认为这更安全——它只是避免了必须使用 unsafe
块。我考虑过 Mutex
,但我认为这也不会让我获得线程安全。
重新设计代码以使用结构进行存储并不是真正的选择。
我认为最好的选择是使用带有互斥量的全局变量。使用 lazy_static 使其变得简单,并允许在函数
内声明 "global"
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
}
您还可以查看 cached 项目/crate。它用一个简单的宏来记忆函数。
我有这样一个昂贵的功能:
pub fn get_expensive_value(n: u64): u64 {
let ret = 0;
for 0 .. n {
// expensive stuff
}
ret
}
并且它被频繁地使用相同的参数调用。它是纯粹的,所以这意味着它将 return 相同的结果并且可以使用缓存。
如果这是一个结构方法,我会在结构中添加一个成员作为缓存,但事实并非如此。所以我的选择似乎是使用静态:
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
。我可以将 RefCell
放在 const
中,而不是 static mut
。但我不认为这更安全——它只是避免了必须使用 unsafe
块。我考虑过 Mutex
,但我认为这也不会让我获得线程安全。
重新设计代码以使用结构进行存储并不是真正的选择。
我认为最好的选择是使用带有互斥量的全局变量。使用 lazy_static 使其变得简单,并允许在函数
内声明 "global"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
}
您还可以查看 cached 项目/crate。它用一个简单的宏来记忆函数。