use std::cell::UnsafeCell; pub struct OnceCell { inner: UnsafeCell>, } impl OnceCell { pub fn new() -> OnceCell { OnceCell { inner: UnsafeCell::new(None) } } pub fn get(&self) -> Option<&T> { unsafe { &*self.inner.get() }.as_ref() } pub fn set(&self, value: T) -> Result<(), T> { let slot = unsafe { &mut *self.inner.get() }; if slot.is_some() { return Err(value); } *slot = Some(value); Ok(()) } // UB!!! pub fn get_or_init(&self, f: impl FnOnce() -> T) -> &T { let slot = unsafe { &mut *self.inner.get() }; match slot { None => { *slot = Some(f()); slot.as_ref().unwrap() } Some(val) => val, } } } pub fn main() { let cell: OnceCell> = OnceCell::new(); let mut r1: Option<&i32> = None; let r2: &i32 = cell.get_or_init(|| { r1 = Some(cell.get_or_init(|| Box::new(1))); // r1 = Some(&*cell.get_or_init(|| Box::new(1))); Box::new(2) }); let r1: &i32 = r1.unwrap(); println!("{} {}", r1, r2); } /* result is like ~/rust ❯❯❯ ./once_cell -1317687192 2 */