2016-03-26 19 views
2

Böyle pahalı bir işlevi vardır:Yapılandırma yöntemi olmayan bir işleve önbelleğe almanın deyimsel yolu nedir?

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

Ve aynı argümanı ile çok sık çağrılır. Bu saf, yani aynı sonucu döndürecek ve bir önbellekten faydalanabileceği anlamına gelir.

Bu bir yapı yöntemi olsaydı, önbellek gibi davranan yapıya üye eklerdim, ancak değil. Yani benim seçenek statik kullanmak gibi görünüyor: Şimdi

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 
    } 
} 

, ben unsafe kullanmak zorunda kalmıştım. static mut yerine, bir RefCell bir const içine koyabilirsiniz. Ama ben daha güvenli olduğuna inanmıyorum - sadece unsafe bloğunu kullanmaktan kaçınıyor. Bir Mutex'u düşündüm, ama bunun da iplik güvenliği sağlayacağını sanmıyorum.

Depolama için bir yapı kullanılacak kodun yeniden tasarlanması gerçekten bir seçenek değildir.

+0

Yinelenen içinde "küresel" beyanı verir [I küresel, değişken singleton yaratabilirim?] (http://stackoverflow.com/questions/27791532/how- do-i-create-a-küresel-değişken-singleton). – Shepmaster

+0

Veya önbelleği başka bir parametre olarak kabul etmek için 'cached_expensive' imzasını değiştirebilirsiniz. – Shepmaster

+0

Bunun bir kopya olduğunu sanmıyorum. Benim sorum özellikle önbelleğe alma ile ilgilidir ve başlangıç ​​noktam küresel, değişken bir tekil olsa da, tesadüfi ve iyi bir çözüm (örneğin) bir "RefCell" veya "Mutex" in bunu nasıl daha iyi hale getirebileceğini veya tamamen nasıl olabileceğini açıklayabilir yapısal olarak farklı bir alternatif. –

cevap

1

Bence en iyi alternatif, global bir değişkeni muteks ile kullanmaktır. lazy_static kullanma kolaylaştırır ve fonksiyon

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 
} 
+0

Bunun bir yinelenen olduğunu kabul ediyorum [Nasıl global, mutable bir singleton nasıl oluşturabilirim?] (Http://stackoverflow.com/questions/27791532/how yorumlarda önerildiği gibi -do-i-create-a-global-mutable-singleton)? – Shepmaster

+0

Evet. Ama cevabı, global değişkenin işlev içinde bildirilebileceğini göstermek için yazmaya karar verdim, bu yüzden kapsam yereldir. – malbarbo

İlgili konular