once_cell for Rust: A Complete Guide with Examples

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

once_cell Library for Rust: Lazy Initialization and Once Cells

\n\n

What It Is and Why You Need It

\n\n

The once_cell library is one of the most popular and useful libraries in the Rust ecosystem, designed to implement the lazy initialization pattern and create once cells. It provides two key types: OnceCell and Lazy, which solve a fundamental problem — deferred creation of a value that is initialized only once upon first access.

\n\n

Why is this needed? In Rust, as in any other language, a situation often arises where creating an object is an expensive operation (for example, reading a configuration file, establishing a database connection, loading a large dictionary). If such an object is not needed immediately when the program starts, but may only be required under certain conditions, its initialization can be deferred. once_cell does this safely and efficiently, guaranteeing that initialization occurs exactly once, even with concurrent access from multiple threads.

\n\n

Before once_cell appeared in the Rust standard library (since version 1.70.0, std::cell::OnceCell and std::sync::OnceLock are available), this library was the de facto standard for lazy initialization. It remains relevant today due to its maturity, wide range of features, and backward compatibility. The library provides not only thread-safe (sync) but also single-threaded (unsync) versions of the types, allowing you to avoid synchronization overhead where it is not needed.

\n\n

Installation

\n\n

To use once_cell, add it to the dependencies of your Cargo.toml project:

\n\n
[dependencies]\nonce_cell = "1.20"
\n\n

Or run the command:

\n\n
cargo add once_cell
\n\n

After that, you can import the necessary types:

\n\n
use once_cell::sync::{OnceCell, Lazy};\n// or for single-threaded use:\nuse once_cell::unsync::{OnceCell as UnsyncOnceCell, Lazy as UnsyncLazy};
\n\n

Quick Start

\n\n

A minimal working example using Lazy for lazy initialization of a static variable:

\n\n
use once_cell::sync::Lazy;\nuse std::collections::HashMap;\n\n// The static variable will be initialized only on first access\nstatic CONFIG: Lazy<HashMap<String, String>> = Lazy::new(|| {\n    println!("Initializing configuration...");\n    let mut map = HashMap::new();\n    map.insert("host".to_string(), "localhost".to_string());\n    map.insert("port".to_string(), "8080".to_string());\n    map\n});\n\nfn main() {\n    // First access — initialization happens here\n    println!("Host: {}", CONFIG.get("host").unwrap());\n    \n    // Second access — initialization does NOT happen, cached value is used\n    println!("Port: {}", CONFIG.get("port").unwrap());\n}
\n\n

Program output:

\n\n
Initializing configuration...\nHost: localhost\nPort: 8080
\n\n

Main Methods and Functions

\n\n

Let's look at 8 key methods and functions of the once_cell library with usage examples.

\n\n

1. OnceCell::new()

\n\n

Signature: pub const fn new() -> OnceCell<T>

\n\n

What it does: Creates a new empty cell that does not yet contain a value.

\n\n
use once_cell::sync::OnceCell;\n\nlet cell: OnceCell<i32> = OnceCell::new();\nassert!(cell.get().is_none()); // The cell is empty
\n\n

2. OnceCell::set()

\n\n

Signature:

Recommendations