Probably the most common thing std::sync::Once is used for is to ensure safe lazy initialization of a global, like this:
use std::sync::{Once, ONCE_INIT};
fn expensive_integer() -> i32 {
static mut EXPENSIVE_INTEGER: i32 = 0;
static mut EXPENSIVE_INTEGER_INIT: Once = ONCE_INIT;
EXPENSIVE_INTEGER_INIT.call_once(|| {
unsafe { EXPENSIVE_INTEGER = /* expensive computation */; }
});
unsafe { EXPENSIVE_INTEGER }
}
This is repetitive and requires unsafe blocks. I’d like to suggest a wrapper that can be used like this instead
use std::sync::InitOnce;
static expensive_integer: InitOnce<i32> = InitOnce::new(|| /* expensive computation */);
Under the hood it’s doing the exact same thing, and then implementing Deref so that it looks like a normal immutable value of type T to consumers.
In addition to being shorter and not requiring application code to use unsafe, please note that in my first example, all of the expensive computation is inside an unsafe block, unless the author takes special care to hoist it. In the second example, that naturally doesn’t happen.
What do people think? This seems simple enough that I may just implement it and send a PR unless everyone hates it.
(Yes, this is essentially what lazy_static does with different syntax. You can’t always use third party crates.)