3 ms·
You can do that in Rust by creating your own abstraction around `UnsafeCell`. Say `InitializeCell`: use std::cell::UnsafeCell; use std::mem::MaybeUnini
by heinrich5991 6y ago
You can do that in Rust by creating your own abstraction around `UnsafeCell`. Say `InitializeCell`:
use std::cell::UnsafeCell;
use std::mem::MaybeUninit;
use std::ops;
pub struct InitializeCell<T> {
inner: UnsafeCell<MaybeUninit<T>>,
}
unsafe impl<T> Sync for InitializeCell<T> {}
impl<T> InitializeCell<T> {
pub const unsafe fn new_uninitialized() -> InitializeCell<T> {
InitializeCell {
inner: UnsafeCell::new(MaybeUninit::uninit()),
}
}
pub const fn new(init: T) -> InitializeCell<T> {
InitializeCell {
inner: UnsafeCell::new(MaybeUninit::new(init)),
}
}
pub unsafe fn init(&self, init: T) {
(*self.inner.get()) = MaybeUninit::new(init);
}
}
impl<T> ops::Deref for InitializeCell<T> {
type Target = T;
fn deref(&self) -> &T {
unsafe {
&*(*self.inner.get()).as_ptr()
}
}
}
static VALUE: InitializeCell<i32> = unsafe { InitializeCell::new_uninitialized() };
static OTHER_VALUE: InitializeCell<i32> = InitializeCell::new(6);
fn main() {
unsafe {
VALUE.init(5);
}
println!("{}", *VALUE);
println!("{}", *OTHER_VALUE);
}
- richard_todd 6y agoThat's actually really nice. It does appear that Rust will peel all the layers away when opt-level is 2 or higher. I could live with that. You can (re)set the value from anywhere, but at least it has to be marked unsafe. Fair enough! When I tried to do this a couple years ago (with mem::uninitialized), I failed to get something usable. I think I was also concerned that having to use unsafe for the reads would prohibit compiler optimizations, even if it could be wrapped in a safe wrapper as you did here. Maybe that was worrying for nothing. Maybe it's time to try Rust again.
- deleted 6y ago[deleted]