once_cell
provides two new cell-like types, unsync::OnceCell
and sync::OnceCell
. OnceCell
might store arbitrary non-Copy
types, can be assigned to at most once and provide direct access
to the stored contents. In a nutshell, API looks roughly like this:
rust,no-run
impl OnceCell<T> {
fn set(&self, value: T) -> Result<(), T> { ... }
fn get(&self) -> Option<&T> { ... }
}
Note that, like with RefCell
and Mutex
, the set
method requires only a shared reference.
Because of the single assignment restriction get
can return an &T
instead of ReF<T>
or MutexGuard<T>
.
OnceCell
might be useful for a variety of patterns.
```rust use std::{env, io}; use once_cell::sync::OnceCell;
pub struct Logger {
// ...
}
static INSTANCE: OnceCell
impl Logger { pub fn global() -> &'static Logger { INSTANCE.get().expect("logger is not initialized") }
fn from_cli(args: env::Args) -> Result<Logger, io::Error> {
// ...
}
}
fn main() -> Result<(), io::Error> {
let logger = Logger::from_cli(env::args())?;
INSTANCE.set(logger).unwrap();
// use Logger::global()
from now on
Ok(())
}
```
This is essentially lazy_static!
macro, but without a macro.
```rust use std::{sync::Mutex, collections::HashMap}; use once_cell::sync::OnceCell;
fn globaldata() -> &'static Mutex
There are also sync::Lazy
and unsync::Lazy
convenience types and macros
to streamline this pattern:
```rust
extern crate once_cell;
use std::{sync::Mutex, collections::HashMap}; use once_cell::sync::Lazy;
static GLOBALDATA: Lazy
fn main() { println!("{:?}", GLOBAL_DATA.lock().unwrap()); } ```
Unlike lazy_static!
, Lazy
works with local variables.
```rust use once_cell::unsync::Lazy;
fn main() {
let ctx = vec![1, 2, 3];
let thunk = Lazy::new(|| {
ctx.iter().sum::
If you need a lazy field in a struct, you probably should use OnceCell
directly, because that will allow you to access self
during initialization.
```rust use std::{fs, io, path::PathBuf}; use once_cell::unsync::OnceCell;
struct Ctx {
config_path: PathBuf,
config: OnceCell
impl Ctx { pub fn getconfig(&self) -> Result<&str, io::Error> { let cfg = self.config.getortryinit(|| { fs::readtostring(&self.configpath) })?; Ok(cfg.asstr()) } } ```
Implementation is based on lazy_static
and
lazy_cell
crates and in some sense just streamlines and
unifies the APIs of those crates.
To implement a sync flavor of OnceCell
, this crates uses either ::std::sync::Once
or
::parking_lot::Once
. This is controlled by the parking_lot
feature, which is enabled by default.
When using parking_lot
, the crate is compatible with rustc 1.25.0, without parking_lot
a minimum
of 1.29.0
is required.
This crate uses unsafe.