以下のコードは動作します。 x
とys
が遅延しており、それぞれFoo::x: Cell
,Foo::ys: RefCell
にキャッシュされています。`Cell`と` RefCell`を使ってmemoizeやlazyを評価する慣用句
しかし、もっと良い方法があると思います。私はラッパーを作る必要がありませんCacheVecGuard
ので、私は&self.ys.borrow().1
の代わりにself.borrow_ys()
を使用できるコールサイトでは、
このコードを改善するにはどうすればよいですか?
この場合に適した遅延評価またはメモを行う標準的なスニペットはありますか? (私はフィットしないlazy_static
の認識しています)
use std::cell::{RefCell, Cell, Ref};
use std::ops::Deref;
struct CacheVecGuard<'a>(Ref<'a, (bool, Vec<f64>)>);
impl<'a> Deref for CacheVecGuard<'a> {
type Target = [f64];
fn deref(&self) -> &Self::Target {
&(self.0).1
}
}
fn pre_calculate_x(x: f64) -> f64 {
x
}
fn pre_calculate_ys(x: f64, ys: &mut [f64]) {
for i in 0..ys.len() {
ys[i] += 1.0;
}
}
struct Foo {
pub a: f64,
x: Cell<Option<f64>>,
ys: RefCell<(bool, Vec<f64>)>,
}
impl Foo {
pub fn new(a: f64) -> Self {
Self {
a,
x: Cell::new(None),
ys: RefCell::new((false, vec![0.0; 10])),
}
}
fn get_x(&self) -> f64 {
match self.x.get() {
None => {
let x = pre_calculate_x(self.a);
self.x.set(Some(x));
println!("Set x to {}", x);
x
}
Some(x) => x,
}
}
fn borrow_ys(&self) -> CacheVecGuard {
{
let (ref mut ready, ref mut ys) = *self.ys.borrow_mut();
if !*ready {
pre_calculate_ys(self.a, ys);
println!("Set ys to {:?}", ys);
*ready = true;
}
}
CacheVecGuard(self.ys.borrow())
}
fn clear_cache(&mut self) {
*(&mut self.ys.borrow_mut().0) = false;
self.x.set(None);
}
pub fn test(&self) -> f64 {
self.borrow_ys()[0] + self.get_x()
}
pub fn set_a(&mut self, a: f64) {
self.a = a;
self.clear_cache();
}
}
fn main() {
let mut foo = Foo::new(1.0);
println!("{}", foo.test());
foo.set_a(3.0);
println!("{}", foo.test());
}
それはあなたのキャッシュをクリアする能力を必要とするという事実は、あなたが持っている必要があることを意味し
Set ys to [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
Set x to 1
2
Set ys to [2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
Set x to 3
5