Things on this page are fragmentary and immature notes/thoughts of the author. Please read with your own judgement!
Tips and Traps¶
std::cell::OnceCell is a partial implementation of
once_cellin the Rust standard library.There are 2 Rust crates lazy_static and once_cell for (lazy) once assignment (which can be used to create singletons). once_cell is preferred to lazy_static for a few reasons .
once_cell is both more flexible and more convenient than lazy_static .
Unlike once_cell , lazy_static supports spinlock-based implementation of blocking which works with
#![no_std].once_cell will likely be part of the Rust standard library in future.
Once assignment means that you can only assign value to such a variable once. However, it is still possible to mutate the variable after initialization.
When defining a static variable which implements Copy, you can define it as a static reference. This helps avoiding accidental implicity copies. The more idiomatic way is to define a wrapper non-Copy struct so that you can be sure that the underlying data won’t get copied.
:timing
:sccache 1
:dep once_cell = "1.13.0"Timing: true
sccache: true
use std::{sync::Mutex, collections::HashMap};
use once_cell::sync::Lazy;Create a Mutable Static Variable (Singleton)¶
static GLOBAL_DATA_1: Lazy<Mutex<HashMap<i32, String>>> = Lazy::new(|| {
let mut m = HashMap::new();
m.insert(13, "Spica".to_string());
m.insert(74, "Hoyten".to_string());
Mutex::new(m)
});GLOBAL_DATA_1.lock().unwrap().insert(1, "New change".to_string());
GLOBAL_DATA_1.lock().unwrap().get(&1)Some("New change")Create a Immutable Static Variable (Singleton)¶
Mutex allows threads to mutate the static variable after initialization. It is not necessary if you just need a readable static variable (after initialization).
static GLOBAL_DATA_2: Lazy<HashMap<i32, String>> = Lazy::new(|| {
let mut m = HashMap::new();
m.insert(13, "Spica".to_string());
m.insert(74, "Hoyten".to_string());
m
});GLOBAL_DATA_2.insert(1, "New change".to_string());
GLOBAL_DATA_2.get(&1)[E0596] Error: cannot borrow immutable static item `GLOBAL_DATA_2` as mutable
╭─[command_6:1:1]
│
1 │ GLOBAL_DATA_2.insert(1, "New change".to_string());
· ────────────────────────┬────────────────────────
· ╰────────────────────────── cannot borrow as mutable
·
· Note: You can change an existing variable to mutable like: `let mut x = x;`
───╯GLOBAL_DATA_2.get(&13)Some("Spica")Lazy Referencing Lazy¶
static GLOBAL_DATA_3: Lazy<[Lazy<&[usize]>; 2]> = Lazy::new(|| {
let mut arr: [Lazy<&[usize]>; 2] = [
Lazy::new(|| &[]),
Lazy::new(|| &[]),
];
arr[0] = Lazy::new(|| &[1, 2, 3]);
arr[1] = Lazy::new(|| &[4, 5, 6, 7]);
arr
});GLOBAL_DATA_3Lazy { cell: OnceCell(Uninit), init: ".." }let x1: &[usize] = &GLOBAL_DATA_3[0];
x1[1, 2, 3]let x2: &[usize] = &GLOBAL_DATA_3[1];
x2[4, 5, 6, 7]