2017-06-15 4 views
0

以下のコードは動作します。 xysが遅延しており、それぞれ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 

Playground

答えて

2

を印刷しますガード。そうでない場合は、set_aを呼び出すと、先に返された裸の参照が無効になります。borrow_ysコンパイラーがこれが起こらないことを確認できる唯一の方法は、ガードを戻し、代わりにガードから借りることです。

キャッシュをクリアする機能を使用できない場合は、代わりにlazycellLazyCellタイプを使用できます。

関連する問題