93. MaybeUninit Array Conversions — Build Fixed Arrays Without transmute
Ever tried to build a [T; N] element-by-element and ended up reaching for mem::transmute because [MaybeUninit<T>; N] refused to convert? Rust 1.95 stabilises safe conversions between [MaybeUninit<T>; N] and MaybeUninit<[T; N]> — no transmute, no tricks.
The old pain
You want a fully-initialised [T; N], but T isn’t Default (or the init is fallible, or expensive). The canonical pattern is:
- Allocate
[MaybeUninit<T>; N]uninitialised. - Fill each slot.
- Get a
[T; N]out the other end.
Step 3 is where it got ugly. MaybeUninit::assume_init only works on MaybeUninit<T>, not [MaybeUninit<T>; N]. To flip the array-of-uninits into uninit-of-array, you reached for mem::transmute — which works, but leans on layout assumptions and carries a big “here be dragons” vibe.
The fix: From conversions
Rust 1.95 stabilises both directions of the conversion, so no transmute is needed:
| |
MaybeUninit::from takes the array-of-uninits and gives you an uninit-of-array ready to assume_init. Safe, obvious, no layout assumption on your part.
The reverse direction
You can also go the other way — from MaybeUninit<[T; N]> back to [MaybeUninit<T>; N] — useful when you want to touch elements individually:
| |
Plus AsRef / AsMut for free
The same release adds AsRef<[MaybeUninit<T>; N]> and AsMut<[MaybeUninit<T>; N]> (plus slice versions) for MaybeUninit<[T; N]>. That means you can borrow the uninit array as a slice without any conversion ceremony:
| |
The helper writes through the AsMut slice view; the caller gets a fully-initialised [u32; 4] after assume_init. No transmute, no pointer casting.
When to reach for it
This is niche — you don’t need it until you’re writing generic collection code, FFI wrappers, or allocator-like APIs that build arrays without Default. But when you do, the new conversions delete an uncomfortable transmute from your codebase and make the intent explicit.
Stabilised in Rust 1.95 (April 2026).