OnceCell Use
This page was last reviewed on Jun 21, 2023.
Dot Net Perls
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.
Example. 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.
Step 1 We create a OnceCell with the new() function. This does not initialize the Test struct inside of it yet.
Step 2 We pass a OnceCell reference to a function. We can use a single OnceCell across many function calls.
Step 3 We use a for-range loop to iterate over a range of numbers. This makes the program more complicated to reason about.
Step 4 We initialize the 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
Benefits. 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.
And We can initialize only when needed, which makes our program easier to write and reason about later.
Single-thread. With 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.
Tip Consider 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.
Dot Net Perls is a collection of tested code examples. Pages are continually updated to stay current, with code correctness a top priority.
Sam Allen is passionate about computer languages. In the past, his work has been recommended by Apple and Microsoft and he has studied computers at a selective university in the United States.
This page was last updated on Jun 21, 2023 (new).
© 2007-2024 Sam Allen.