Shared State Patterns
RefCell Cache
Fill Once, Read Later
RefCell<Option<T>> can model a cache that starts empty and is filled when the value is first requested.
Program
Play the program to choose a source value and store it in a small cache.
refcell_cache.rs
Replay: real traced execution (multi-file project)
use std::cell::RefCell;
fn main() {
let source = "primary";
let cache = RefCell::new(None);
let value = cached_value(&cache, source);
println!("{value}");
}
fn cached_value(cache: &RefCell<Option<String>>, source: &str) -> String {
if cache.borrow().is_none() {
*cache.borrow_mut() = Some(source.to_string());
}
cache.borrow().clone().unwrap()
}
use std::cell::RefCell;
fn main() {
let source = "backup";
let cache = RefCell::new(None);
let value = cached_value(&cache, source);
println!("{value}");
}
fn cached_value(cache: &RefCell<Option<String>>, source: &str) -> String {
if cache.borrow().is_none() {
*cache.borrow_mut() = Some(source.to_string());
}
cache.borrow().clone().unwrap()
}
use std::cell::RefCell;
fn main() {
let source = "none";
let cache = RefCell::new(None);
let value = cached_value(&cache, source);
println!("{value}");
}
fn cached_value(cache: &RefCell<Option<String>>, source: &str) -> String {
if cache.borrow().is_none() {
*cache.borrow_mut() = Some(source.to_string());
}
cache.borrow().clone().unwrap()
}
source ← "primary", cache ← RefCell { value: None }
3fn main() {4 let sourc→ "primary"e = "primary"; //@source="primary", "backup", "none"5 let cach→ RefCell { value: None }e = RefCell::new(None);6 let value = cached_value(&cachRefCell { value: None }e, sourc"primary"e);7 println!("{value}");cache.borrow().clone().unwrap()
13 }14 cache.borrow().clone().unwrap()15}cache ← RefCell { value: Some("primary") }, value ← "primary"
5 let cache = RefCell::new(None);6 let valu→ "primary"e = cached_value(&cach→ RefCell { value: Some("primary") }e, sourc"primary"e);7 println!("{value}");8}outputprimary
source ← "backup", cache ← RefCell { value: None }
3fn main() {4 let sourc→ "backup"e = "backup";5 let cach→ RefCell { value: None }e = RefCell::new(None);6 let value = cached_value(&cachRefCell { value: None }e, sourc"backup"e);7 println!("{value}");cache.borrow().clone().unwrap()
13 }14 cache.borrow().clone().unwrap()15}cache ← RefCell { value: Some("backup") }, value ← "backup"
5 let cache = RefCell::new(None);6 let valu→ "backup"e = cached_value(&cach→ RefCell { value: Some("backup") }e, sourc"backup"e);7 println!("{value}");8}outputbackup
source ← "none", cache ← RefCell { value: None }
3fn main() {4 let sourc→ "none"e = "none";5 let cach→ RefCell { value: None }e = RefCell::new(None);6 let value = cached_value(&cachRefCell { value: None }e, sourc"none"e);7 println!("{value}");cache.borrow().clone().unwrap()
13 }14 cache.borrow().clone().unwrap()15}cache ← RefCell { value: Some("none") }, value ← "none"
5 let cache = RefCell::new(None);6 let valu→ "none"e = cached_value(&cach→ RefCell { value: Some("none") }e, sourc"none"e);7 println!("{value}");8}outputnone
Option cache
`None` means the cache is empty; `Some(value)` stores the computed data.
borrow_mut
`borrow_mut` opens a checked mutable borrow for filling the cache.
clone
The helper returns an owned `String` so the borrow does not escape the function.