Struct LazyLock

struct LazyLock<T, F = fn() -> T> { ... }

A value which is initialized on the first access.

This type is a thread-safe LazyCell, and can be used in statics. Since initialization may be called from multiple threads, any dereferencing call will block the calling thread if another initialization routine is currently running.

Poisoning

If the initialization closure passed to LazyLock::new panics, the lock will be poisoned. Once the lock is poisoned, any threads that attempt to access this lock (via a dereference or via an explicit call to force()) will panic.

This concept is similar to that of poisoning in the std::sync::poison module. A key difference, however, is that poisoning in LazyLock is unrecoverable. All future accesses of the lock from other threads will panic, whereas a type in std::sync::poison like std::sync::poison::Mutex allows recovery via PoisonError::into_inner().

Examples

Initialize static variables with LazyLock.

use std::sync::LazyLock;

// Note: static items do not call [`Drop`](Drop) on program termination, so this won't be deallocated.
// this is fine, as the OS can deallocate the terminated program faster than we can free memory
// but tools like valgrind might report "memory leaks" as it isn't obvious this is intentional.
static DEEP_THOUGHT: LazyLock<String> = LazyLock::new(|| {
# mod another_crate {
#     pub fn great_question() -> String { "42".to_string() }
# }
    // M3 Ultra takes about 16 million years in --release config
    another_crate::great_question()
});

// The `String` is built, stored in the `LazyLock`, and returned as `&String`.
let _ = &*DEEP_THOUGHT;

Initialize fields with LazyLock.

use std::sync::LazyLock;

#[derive(Debug)]
struct UseCellLock {
    number: LazyLock<u32>,
}
fn main() {
    let lock: LazyLock<u32> = LazyLock::new(|| 0u32);

    let data = UseCellLock { number: lock };
    println!("{}", *data.number);
}

Implementations

impl<T, F> LazyLock<T, F>

fn get_mut(this: &mut LazyLock<T, F>) -> Option<&mut T>

Returns a mutable reference to the value if initialized. Otherwise (if uninitialized or poisoned), returns None.

Examples

use std::sync::LazyLock;

let mut lazy = LazyLock::new(|| 92);

assert_eq!(LazyLock::get_mut(&mut lazy), None);
let _ = LazyLock::force(&lazy);
*LazyLock::get_mut(&mut lazy).unwrap() = 44;
assert_eq!(*lazy, 44);
fn get(this: &LazyLock<T, F>) -> Option<&T>

Returns a reference to the value if initialized. Otherwise (if uninitialized or poisoned), returns None.

Examples

use std::sync::LazyLock;

let lazy = LazyLock::new(|| 92);

assert_eq!(LazyLock::get(&lazy), None);
let _ = LazyLock::force(&lazy);
assert_eq!(LazyLock::get(&lazy), Some(&92));

impl<T, F: FnOnce() -> T> LazyLock<T, F>

const fn new(f: F) -> LazyLock<T, F>

Creates a new lazy value with the given initializing function.

Examples

use std::sync::LazyLock;

let hello = "Hello, World!".to_string();

let lazy = LazyLock::new(|| hello.to_uppercase());

assert_eq!(&*lazy, "HELLO, WORLD!");
fn into_inner(this: Self) -> Result<T, F>

Consumes this LazyLock returning the stored value.

Returns Ok(value) if Lazy is initialized and Err(f) otherwise.

Panics

Panics if the lock is poisoned.

Examples

#![feature(lazy_cell_into_inner)]

use std::sync::LazyLock;

let hello = "Hello, World!".to_string();

let lazy = LazyLock::new(|| hello.to_uppercase());

assert_eq!(&*lazy, "HELLO, WORLD!");
assert_eq!(LazyLock::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string()));
fn force_mut(this: &mut LazyLock<T, F>) -> &mut T

Forces the evaluation of this lazy value and returns a mutable reference to the result.

Panics

If the initialization closure panics (the one that is passed to the new() method), the panic is propagated to the caller, and the lock becomes poisoned. This will cause all future accesses of the lock (via force() or a dereference) to panic.

Examples

use std::sync::LazyLock;

let mut lazy = LazyLock::new(|| 92);

let p = LazyLock::force_mut(&mut lazy);
assert_eq!(*p, 92);
*p = 44;
assert_eq!(*lazy, 44);
fn force(this: &LazyLock<T, F>) -> &T

Forces the evaluation of this lazy value and returns a reference to result. This is equivalent to the Deref impl, but is explicit.

This method will block the calling thread if another initialization routine is currently running.

Panics

If the initialization closure panics (the one that is passed to the new() method), the panic is propagated to the caller, and the lock becomes poisoned. This will cause all future accesses of the lock (via force() or a dereference) to panic.

Examples

use std::sync::LazyLock;

let lazy = LazyLock::new(|| 92);

assert_eq!(LazyLock::force(&lazy), &92);
assert_eq!(&*lazy, &92);

impl<P, T> Receiver for LazyLock<T, F>

impl<T> Any for LazyLock<T, F>

fn type_id(self: &Self) -> TypeId

impl<T> Borrow for LazyLock<T, F>

fn borrow(self: &Self) -> &T

impl<T> BorrowMut for LazyLock<T, F>

fn borrow_mut(self: &mut Self) -> &mut T

impl<T> From for LazyLock<T, F>

fn from(t: T) -> T

Returns the argument unchanged.

impl<T, F = fn() -> T> Freeze for LazyLock<T, F>

impl<T, F> Drop for LazyLock<T, F>

fn drop(self: &mut Self)

impl<T, F> Send for LazyLock<T, F>

impl<T, F> Unpin for LazyLock<T, F>

impl<T, F> UnsafeUnpin for LazyLock<T, F>

impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F>

fn deref(self: &Self) -> &T

Dereferences the value.

This method will block the calling thread if another initialization routine is currently running.

Panics

If the initialization closure panics (the one that is passed to the new() method), the panic is propagated to the caller, and the lock becomes poisoned. This will cause all future accesses of the lock (via force() or a dereference) to panic.

impl<T, F: FnOnce() -> T> DerefMut for LazyLock<T, F>

fn deref_mut(self: &mut Self) -> &mut T

Panics

If the initialization closure panics (the one that is passed to the new() method), the panic is propagated to the caller, and the lock becomes poisoned. This will cause all future accesses of the lock (via force() or a dereference) to panic.

impl<T, U> Into for LazyLock<T, F>

fn into(self: Self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of [From]<T> for U chooses to do.

impl<T, U> TryFrom for LazyLock<T, F>

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

impl<T, U> TryInto for LazyLock<T, F>

fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error>

impl<T: Default> Default for LazyLock<T>

fn default() -> LazyLock<T>

Creates a new lazy value using Default as the initializing function.

impl<T: RefUnwindSafe + UnwindSafe, F: UnwindSafe> RefUnwindSafe for LazyLock<T, F>

impl<T: Sync + Send, F: Send> Sync for LazyLock<T, F>

impl<T: UnwindSafe, F: UnwindSafe> UnwindSafe for LazyLock<T, F>

impl<T: fmt::Debug, F> Debug for LazyLock<T, F>

fn fmt(self: &Self, f: &mut Formatter<'_>) -> Result