136. LazyLock::force_mut — Mutate a Lazy Value Without Wrapping It in a Mutex
Got a LazyLock you own outright? With force_mut (stable in Rust 1.94), you can initialize and mutate it through &mut LazyLock — no Mutex, no RwLock, no locking dance.
The Problem
LazyLock is perfect for one-time initialization, but its Deref only hands out a shared reference. If you want to mutate the inner value, the textbook move is to wrap it in Mutex<T>:
| |
That’s the right answer for shared global state. But when you actually have exclusive ownership — a struct field, a builder, a test fixture — the Mutex is pure ceremony.
force_mut: Init and Mutate in One Step
If you have &mut LazyLock<T>, you already have exclusive access. Synchronization is moot. force_mut exploits that: it triggers initialization if needed, then hands you a plain &mut T.
| |
No Mutex, no .lock().unwrap(), no poisoning to handle. The init closure runs at most once, and from then on you can mutate freely through &mut.
get_mut: Mutate Only If Already Initialized
The sibling, LazyLock::get_mut, returns Option<&mut T> and won’t trigger init:
| |
Useful when you’d rather skip work entirely if it never happened — “flush the cache on shutdown, but only if anyone built it.”
When to Reach for It
Pick force_mut whenever you own the LazyLock outright and would otherwise wrap it in Mutex<T> just to get mutation. It’s perfect for struct fields, test fixtures, builders, and anything else where you already have &mut to the container.
LazyCell::force_mut and LazyCell::get_mut ship the same shape for the single-thread cell — pick whichever matches your sync story.