OnceCell
Suppose we have a struct
that is expensive to initialize, and might not always be needed. Or we want to wait to initialize it until the last moment possible.
For lazy initialization in Rust, OnceCell
is useful. It can help us write logic on a single thread that delays or avoids initializing an expensive type.
Consider this program—like many real-world programs, it has some complicated logic in a function. It can be hard to determine when or if our Test struct
is even needed.
OnceCell
with the new()
function. This does not initialize the Test struct
inside of it yet.OnceCell
reference to a function. We can use a single OnceCell
across many function calls.for-range
loop to iterate over a range of numbers. This makes the program more complicated to reason about.OnceCell
on 2 different conditions. It is only initialized once, even though it is accessed twice.use std::cell::OnceCell; struct Test { value: String, } fn init_test(i: usize) -> Test { // Store value string in struct. Test { value: i.to_string(), } } fn main() { // Step 1: create OnceCell. let test = OnceCell::new(); // Step 2: pass OnceCell to function. compute(&test); } fn compute(test: &OnceCell<Test>) { // Step 3: loop over some numbers. for i in 1..100 { // Step 4: if one of two conditions is true, initialize the OnceCell if not already initialized. if i == 60 { let result = test.get_or_init(|| init_test(i)); println!("i = 60, value = {}", result.value); } if i % 61 == 0 { let result = test.get_or_init(|| init_test(i)); println!("i % 61 = 0, value = {}", result.value); } } }i = 60, value = 60 i % 61 = 0, value = 60
In a real-world Rust program, we have many functions and conditions. By lazily initializing a struct
, we can save resources if the struct
is never accessed.
Single
-threadWith OnceCell
, we do not have a Sync trait so we cannot cross a thread barrier. This means OnceCell
can only be used on a single thread, and it cannot be static
.
OnceLock
for a Sync-enabled version of OnceCell
. OnceLock
can be used a static
and accessed on multiple threads.By using OnceCell
and its sibling OnceLock
, we can simplify and optimize programs. We delay initialization, which means less setup logic is needed, and this can sometimes avoid work altogether.