使用thread-local!
(如另一个答案中所建议的)来解决这个问题并不是那么简单,所以我在这里提供了一个完整的解决方案:
use std::cell::RefCell;
use std::collections::HashMap;
fn main() {
println!("thread-local demo for Collatz:");
(2..20).for_each(|n| println!("{n}: {c}", n = n, c = collatz(n)));
}
thread_local! (static COLLATZ_CACHE: RefCell<HashMap<usize, usize>> = {
let mut cache = HashMap::new();
cache.insert(1, 0);
RefCell::new(cache)
});
fn collatz(n: usize) -> usize {
COLLATZ_CACHE.with(|cache| {
let entry = cache.borrow().get(&n).copied();
if let Some(v) = entry { v } else {
let v = match n % 2 {
0 => 1 + collatz(n / 2),
1 => 1 + collatz(n * 3 + 1),
_ => unreachable!(),
};
cache.borrow_mut().insert(n, v);
*cache.borrow().get(&n).unwrap()
}
})
}
如果线程本地存储不够全局,那么您可以使用once_cell crate的功能——它也在进入 std(已经在 nightly 中)——初始化一个静态变量:
#![feature(once_cell)]
use std::collections::HashMap;
use std::lazy::SyncLazy;
use std::sync::Mutex;
fn main() {
println!("once_cell demo for Collatz:");
(2..20).for_each(|n| println!("{n}: {c}", n = n, c = collatz(n)));
}
static COLLATZ_CACHE: SyncLazy<Mutex<HashMap<usize, usize>>> = SyncLazy::new(|| {
let mut cache = HashMap::new();
cache.insert(1, 0);
Mutex::new(cache)
});
fn collatz(n: usize) -> usize {
let cache = &COLLATZ_CACHE;
let entry = cache.lock().unwrap().get(&n).copied();
if let Some(v) = entry {
v
} else {
let v = match n % 2 {
0 => 1 + collatz(n / 2),
1 => 1 + collatz(n * 3 + 1),
_ => unreachable!(),
};
cache.lock().unwrap().insert(n, v);
*cache.lock().unwrap().get(&n).unwrap()
}
}
操场