Constants
Declare lazily evaluated constant
Declares a lazily evaluated constant HashMap. The HashMap will
be evaluated once and stored behind a global static reference.
use lazy_static::lazy_static;
use std::collections::HashMap;
lazy_static! {
static ref PRIVILEGES: HashMap<&'static str, Vec<&'static str>> = {
let mut map = HashMap::new();
map.insert("James", vec!["user", "admin"]);
map.insert("Jim", vec!["user"]);
map
};
}
fn show_access(name: &str) {
let access = PRIVILEGES.get(name);
println!("{}: {:?}", name, access);
}
fn main() {
let access = PRIVILEGES.get("James");
println!("James: {:?}", access);
show_access("Jim");
}
Std:cell
OnceCell is included in the standard library as an alternative.
use std::cell::OnceCell;
fn main() {
let cell = OnceCell::new();
assert!(cell.get().is_none());
let value: &String = cell.get_or_init(|| {
"Hello, World!".to_string()
});
assert_eq!(value, "Hello, World!");
assert!(cell.get().is_some());
}
std::cell::LazyCell
The LazyCell type can be used to defer the initialization of a value until the first time it is accessed.
It is useful for expensive computations that might not be needed during the entire execution of a scope.
In this example, we use LazyCell to lazily compute a set of permissions based on a user ID.
Unlike static lazy types, LazyCell can capture local variables from its surrounding scope.
use std::cell::LazyCell;
fn main() {
let user_id = 42;
// The closure is not executed yet.
let permissions = LazyCell::new(|| {
println!("--- Fetching permissions from database for ID {} ---", user_id);
// Simulate an expensive operation
vec!["read".to_string(), "write".to_string()]
});
println!("User {} session started.", user_id);
// The initialization happens only when we dereference permissions for the first time.
if true { // Imagine a conditional check here
println!("Permissions: {:?}", *permissions);
}
// Subsequent accesses use the already initialized value.
println!("First permission: {}", permissions[0]);
}
std::sync::LazyLock
The LazyLock type is a thread-safe version of LazyCell that can be used in static contexts.
It is the standard library alternative to the lazy_static crate for global, lazily initialized data.
The example shows how to use LazyLock to create a global configuration that is loaded once from
the environment upon first access.
use std::sync::LazyLock;
struct Config {
api_key: String,
timeout: u64,
}
// Global configuration initialized on first use.
static APP_CONFIG: LazyLock<Config> = LazyLock::new(|| {
println!("Loading configuration...");
Config {
api_key: std::env::var("API_KEY").unwrap_or_else(|_| "default_key".to_string()),
timeout: 30,
}
});
fn main() {
println!("App started.");
// The initialization happens here.
let timeout = APP_CONFIG.timeout;
println!("Timeout is: {}s", timeout);
println!("API Key is hidden: {}", APP_CONFIG.api_key.len() > 0);
}