pub struct OnceLock<T> { /* private fields */ }
Expand description
A synchronization primitive which can be written to only once.
This type is a thread-safe OnceCell
, and can be used in statics.
§Examples
Using OnceCell
to store a function’s previously computed value (a.k.a.
‘lazy static’ or ‘memoizing’):
use std::sync::OnceLock;
struct DeepThought {
answer: String,
}
impl DeepThought {
fn new() -> Self {
Self {
// M3 Ultra takes about 16 million years in --release config
answer: Self::great_question(),
}
}
}
fn computation() -> &'static DeepThought {
// n.b. static items do not call [`Drop`] on program termination, so if
// [`DeepThought`] impls Drop, that will not be used for this instance.
static COMPUTATION: OnceLock<DeepThought> = OnceLock::new();
COMPUTATION.get_or_init(|| DeepThought::new())
}
// The `DeepThought` is built, stored in the `OnceLock`, and returned.
let _ = computation().answer;
// The `DeepThought` is retrieved from the `OnceLock` and returned.
let _ = computation().answer;
Writing to a OnceLock
from a separate thread:
use std::sync::OnceLock;
static CELL: OnceLock<usize> = OnceLock::new();
// `OnceLock` has not been written to yet.
assert!(CELL.get().is_none());
// Spawn a thread and write to `OnceLock`.
std::thread::spawn(|| {
let value = CELL.get_or_init(|| 12345);
assert_eq!(value, &12345);
})
.join()
.unwrap();
// `OnceLock` now contains the value.
assert_eq!(
CELL.get(),
Some(&12345),
);
Implementations§
source§impl<T> OnceLock<T>
impl<T> OnceLock<T>
sourcepub fn get(&self) -> Option<&T>
pub fn get(&self) -> Option<&T>
Gets the reference to the underlying value.
Returns None
if the cell is empty, or being initialized. This
method never blocks.
sourcepub fn get_mut(&mut self) -> Option<&mut T>
pub fn get_mut(&mut self) -> Option<&mut T>
Gets the mutable reference to the underlying value.
Returns None
if the cell is empty. This method never blocks.
sourcepub fn set(&self, value: T) -> Result<(), T>
pub fn set(&self, value: T) -> Result<(), T>
Sets the contents of this cell to value
.
May block if another thread is currently attempting to initialize the cell. The cell is guaranteed to contain a value when set returns, though not necessarily the one provided.
Returns Ok(())
if the cell’s value was set by this call.
§Examples
use std::sync::OnceLock;
static CELL: OnceLock<i32> = OnceLock::new();
fn main() {
assert!(CELL.get().is_none());
std::thread::spawn(|| {
assert_eq!(CELL.set(92), Ok(()));
}).join().unwrap();
assert_eq!(CELL.set(62), Err(62));
assert_eq!(CELL.get(), Some(&92));
}
sourcepub fn try_insert(&self, value: T) -> Result<&T, (&T, T)>
🔬This is a nightly-only experimental API. (once_cell_try_insert
)
pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)>
once_cell_try_insert
)Sets the contents of this cell to value
if the cell was empty, then
returns a reference to it.
May block if another thread is currently attempting to initialize the cell. The cell is guaranteed to contain a value when set returns, though not necessarily the one provided.
Returns Ok(&value)
if the cell was empty and Err(¤t_value, value)
if it was full.
§Examples
#![feature(once_cell_try_insert)]
use std::sync::OnceLock;
static CELL: OnceLock<i32> = OnceLock::new();
fn main() {
assert!(CELL.get().is_none());
std::thread::spawn(|| {
assert_eq!(CELL.try_insert(92), Ok(&92));
}).join().unwrap();
assert_eq!(CELL.try_insert(62), Err((&92, 62)));
assert_eq!(CELL.get(), Some(&92));
}
sourcepub fn get_or_init<F>(&self, f: F) -> &Twhere
F: FnOnce() -> T,
pub fn get_or_init<F>(&self, f: F) -> &Twhere
F: FnOnce() -> T,
Gets the contents of the cell, initializing it with f
if the cell
was empty.
Many threads may call get_or_init
concurrently with different
initializing functions, but it is guaranteed that only one function
will be executed.
§Panics
If f
panics, the panic is propagated to the caller, and the cell
remains uninitialized.
It is an error to reentrantly initialize the cell from f
. The
exact outcome is unspecified. Current implementation deadlocks, but
this may be changed to a panic in the future.
§Examples
use std::sync::OnceLock;
let cell = OnceLock::new();
let value = cell.get_or_init(|| 92);
assert_eq!(value, &92);
let value = cell.get_or_init(|| unreachable!());
assert_eq!(value, &92);
sourcepub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
🔬This is a nightly-only experimental API. (once_cell_try
)
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
once_cell_try
)Gets the contents of the cell, initializing it with f
if
the cell was empty. If the cell was empty and f
failed, an
error is returned.
§Panics
If f
panics, the panic is propagated to the caller, and
the cell remains uninitialized.
It is an error to reentrantly initialize the cell from f
.
The exact outcome is unspecified. Current implementation
deadlocks, but this may be changed to a panic in the future.
§Examples
#![feature(once_cell_try)]
use std::sync::OnceLock;
let cell = OnceLock::new();
assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
assert!(cell.get().is_none());
let value = cell.get_or_try_init(|| -> Result<i32, ()> {
Ok(92)
});
assert_eq!(value, Ok(&92));
assert_eq!(cell.get(), Some(&92))
sourcepub fn into_inner(self) -> Option<T>
pub fn into_inner(self) -> Option<T>
Consumes the OnceLock
, returning the wrapped value. Returns
None
if the cell was empty.
§Examples
use std::sync::OnceLock;
let cell: OnceLock<String> = OnceLock::new();
assert_eq!(cell.into_inner(), None);
let cell = OnceLock::new();
cell.set("hello".to_string()).unwrap();
assert_eq!(cell.into_inner(), Some("hello".to_string()));
sourcepub fn take(&mut self) -> Option<T>
pub fn take(&mut self) -> Option<T>
Takes the value out of this OnceLock
, moving it back to an uninitialized state.
Has no effect and returns None
if the OnceLock
hasn’t been initialized.
Safety is guaranteed by requiring a mutable reference.
§Examples
use std::sync::OnceLock;
let mut cell: OnceLock<String> = OnceLock::new();
assert_eq!(cell.take(), None);
let mut cell = OnceLock::new();
cell.set("hello".to_string()).unwrap();
assert_eq!(cell.take(), Some("hello".to_string()));
assert_eq!(cell.get(), None);