Lazy Initialization

RecipeCratesCategories
stdcat-memory-management
once_cellonce_cellcat-memory-management
lazy_staticlazy_staticcat-memory-management

Two key libraries:

  • once_cell: newer crate with more ergonomic API. Should be preferred for all new projects.
  • lazy_static: older crate. API is less convenient, but crate is stable and maintained.

The core functionality of once_cell is now included in the standard library with the remaining parts on track to be stabilised in future.

std

std cat-memory-management

OnceCell⮳ is a cell which can be written to only once.

The corresponding Sync version of OnceCell<T> is OnceLock<T>.

use std::cell::OnceCell;

fn main() {
    let cell = OnceCell::new();
    assert!(cell.get().is_none());

    let value: &String = cell.get_or_init(|| "Hello, World!".to_string());
    assert_eq!(value, "Hello, World!");
    assert!(cell.get().is_some());
}

once_cell

once_cell once_cell-crates.io once_cell-github once_cell-lib.rs cat-memory-management cat-rust-patterns

once_cell⮳ provides two cell-like types, unsync::OnceCell and sync::OnceCell. A OnceCell might store arbitrary non-Copy types, can be assigned to at most once and provides direct access to the stored contents. The sync flavor is thread-safe. once_cell also has a once_cell::sync::Lazy⮳ type, build on top of OnceCell⮳:

use std::collections::HashMap;
use std::sync::Mutex;

use once_cell::sync::Lazy;

// must be static, not const
static GLOBAL_DATA: Lazy<Mutex<HashMap<i32, String>>> = Lazy::new(|| {
    let mut m = HashMap::new();
    m.insert(13, "Spica".to_string());
    m.insert(74, "Hoyten".to_string());
    Mutex::new(m)
});

fn main() {
    println!("{:?}", GLOBAL_DATA.lock().unwrap());
}

lazy_static

lazy_static lazy_static-crates.io lazy_static-github lazy_static-lib.rs cat-no-std cat-memory-management cat-rust-patterns