140. slice::as_array — Lock a Slice Into a Fixed-Size Array Reference
A function hands you &[u8] but the next step wants &[u8; 32]. The old answer was <&[u8; 32]>::try_from(slice) — a turbofish-and-trait dance for what is really just a length check. Rust 1.93 stabilises slice::as_array, the method-call version that does exactly that.
The pain: TryFrom for what should be a method
Cryptography APIs, parsers, and FFI all funnel data through &[T], but consumers usually want a concrete &[T; N] so they can index without bounds checks or pattern-match the fields out. The canonical conversion looks like this:
| |
It works, but every time you have to remember to write <&[u8; 32]>::try_from(...) with the reference inside the turbofish — write <[u8; 32]>::try_from instead and you’ll get an owned array (and a T: Clone bound) that you didn’t ask for. The error message when a coworker gets the form wrong is its own little adventure.
The fix: a method on [T] that returns Option<&[T; N]>
<[T]>::as_array::<N> is a plain method call. The length check is the same — the whole slice must be exactly N long — but the call site reads like every other slice method:
| |
No TryFrom import, no angle-brackets-around-a-reference. The turbofish goes on the method, where it belongs, and the return type is Option — which is what you wanted anyway when the conversion can fail.
as_mut_array for the writeable side
The same trick works through &mut [T]. Useful when you’ve been handed a sub-slice of a buffer and want to write a fixed-size record into it without indexing each field:
| |
as_array and as_mut_array mirror <&[T; N]>::try_from / <&mut [T; N]>::try_from exactly — same semantics, fewer keystrokes, better error type.
Pair it with split_first_chunk for parsers
If you only need the first N bytes (and want to keep the rest), reach for split_first_chunk::<N> from the existing family. Use as_array when the slice is supposed to be exactly the right length — return values from a digest() call, decoded base64 of known size, FFI buffers carved to spec:
| |
.copied() turns &[u8; 4] into [u8; 4] when you want an owned array — works because [u8; 4]: Copy.
When to reach for it
Anywhere you currently write <&[T; N]>::try_from(slice).ok() or slice.try_into().ok() and have to annotate the type to steer the inference. as_array is shorter, the failure case is an Option instead of a Result<_, TryFromSliceError>, and the turbofish sits where every other generic slice method puts it. Small ergonomics, but you’ll write it ten times this week.