OnceCell stores a value that can be written exactly once and then accessed afterward. Create an empty cell with OnceCell::new(), initialize it with .set(), and retrieve the value with .get(). section 17.7.2
Unlike a fixed lazy static, OnceCell lets the program provide the value later. For example, a URL can be fetched in main and then used to build a global Logger. Choose the synchronized version when the value must cross threads; otherwise, use the unsynchronized version. section 17.7.2
use once_cell::sync::OnceCell;
use reqwest::Client;
use std::sync::Mutex;
#[derive(Debug)]
struct Logger {
logs: Mutex<Vec<Log>>,
url: String,
client: Client,
}
#[derive(Debug)]
struct Log {
message: String,
timestamp: i64,
}
static GLOBAL_LOGGER: OnceCell<Logger> = OnceCell::new();
fn fetch_url() -> String { #1
#2
"http://somethingsomething.com".to_string() #3
}
fn main() {
let url = fetch_url();
GLOBAL_LOGGER #4
.set(Logger {
logs: Mutex::new(vec![]),
url,
client: Client::default(),
})
.unwrap(); #5
GLOBAL_LOGGER #6
.get() #7
.unwrap()
.logs
.lock() #8
.unwrap()
.push(Log {
message: "Everything's going well".to_string(),
timestamp: 1658930674,
});
println!("{GLOBAL_LOGGER:?}"); #9
}
A complete example creates a thread-safe global OnceCell, sets a Logger after fetching its URL, reads it with get(), and adds a log entry. section 17.7.2
The same design is available through the standard library: std::cell::OnceCell is not thread-safe, while std::sync::OnceLock provides the thread-safe version. The surrounding code is almost unchanged. section 17.7.2

