MaybeUninit and arrays
use std::mem::MaybeUninit; use std::ptr; fn main() { let input = b"RUST"; let mut buf = [const { MaybeUninit::<u8>::uninit() }; 2048]; // Initialize elements by writing values to the memory for (i, input_byte) in input.iter().enumerate() { unsafe { let dst = buf.as_mut_ptr().add(i); ptr::write((*dst).as_mut_ptr(), *input_byte); } } // When a portion of an array is initialized, one can // use unsafe to isolate it let ptr_to_init_subslice = buf.as_ptr() as *const u8; let init = unsafe { std::slice::from_raw_parts(ptr_to_init_subslice, input.len()) }; let text = std::str::from_utf8(init).unwrap(); println!("{text}"); // We must manually drop the initialized elements for element in &mut buf[0..input.len()] { unsafe { element.assume_init_drop(); } } }
To create an array of uninitialized memory, the ::uninit() constructor can be
used within a const context.
Use ptr::write to initialize values as per normal.
.assume_init() does not work as easily for arrays. It requires every value to
be initialized, which may not occur when reusing a buffer. This example uses a
pointer to isolate the initialized bytes to create a string slice.
When creating a sub-slice of a partially-initialized array, be careful with
ownership and correctly implementing drop. Reminder: MaybeUninit<T> will not
call drop on its T.
MaybeUninit<[u8;2048]> is distinct from [MaybeUninit::<u8>; 2048]. This is
the difference between an array of uninitialized memory and an array that
contains uninitialized elements.
MaybeUninit<[u8;2048]>is “all or nothing”. You either fully initialize the whole array and then callassume_init, or you must keep it asMaybeUninit<[u8; 2048]>and avoid touching it as[u8; 2048].[MaybeUninit<u8>; 2048]lets you initialize elements one at a time, then take a sub-slice of just the initialized prefix and treat it as[u8]viastd::slice::from_raw_parts.slice_assume_init_refis safe only when every element in the slice is initialized. For this example, we only pass&buf[..input.len()]after writing exactly those bytes.- When
Tneeds drop, you must manually callassume_init_drop()for the initialized elements. Skipping this leaks memory. However, calling it on an uninitialized element is undefined behavior.