I have an &[u8]
and would like to turn it into an &[u8; 3]
without copying. It should reference the original array. How can I do this?
Asked
Active
Viewed 1.1k times
14

Shepmaster
- 388,571
- 95
- 1,107
- 1,366

SoniEx2
- 1,864
- 3
- 27
- 40
-
`[&x[0], &x[1], &x[2]]`? – Dogbert Jan 06 '18 at 16:51
-
That's an [&u8; 3]. – SoniEx2 Jan 06 '18 at 16:52
-
2Why would you need that? – mcarton Jan 06 '18 at 17:01
-
1Also see the related but different [How to get a slice as an array in Rust?](https://stackoverflow.com/q/25428920/155423) – Shepmaster Jan 06 '18 at 17:11
3 Answers
27
As of Rust 1.34, you can use TryFrom
/ TryInto
:
use std::convert::TryFrom;
fn example(slice: &[u8]) {
let array = <&[u8; 3]>::try_from(slice);
println!("{:?}", array);
}
fn example_mut(slice: &mut [u8]) {
let array = <&mut [u8; 3]>::try_from(slice);
println!("{:?}", array);
}

Shepmaster
- 388,571
- 95
- 1,107
- 1,366
-
1If you're passing it into a function that expects such a parameter, you can also use `try_into().unwrap()` to avoid the need to write out the array type, and if you're sure the slice is large enough. – Stephen Chung Dec 23 '19 at 10:37
9
EDIT: TryFrom
/TryInto
has been stabilized as of Rust 1.34. Please see @shepmaster's answer for an updated method.
Just to re-emphasize, this can't be done without unsafe code because you don't know until runtime that the slice has three elements in it.
fn slice_to_arr3<T>(slice: &[T]) -> Option<&[T; 3]> {
if slice.len() == 3 {
Some(unsafe { &*(slice as *const [T] as *const [T; 3]) })
} else {
None
}
}
This can't be generic over the length of the array until const generics are implemented.

durka42
- 1,502
- 10
- 17
-
6I'd quibble over the phrasing "this can't be safe". It is most definitely *safe* — as long as you check the length of the slice. If it actually could never be safe, then it should never be written in the first place. It's a pedantic argument but the concept of "safety" is muddled enough for Rust newcomers that I find it worth pointing out. – Shepmaster Jan 06 '18 at 17:28
-
1
-
1Yes I agree. Maybe better phrasing is _cannot be done without unsafe code_. – durka42 Jan 06 '18 at 20:42
-
1Nothing can be "done without unsafe code" by that logic since the stdlib necessarily needs unsafe code, everything one shall ever use internally has that. I think the correct phrasing is "this problem has no total solution"; any solution to it has to be partial and account for the error case where the slice does not have at least 3 elements, somehow. – Zorf Jan 10 '20 at 21:14
-
2@Zorf the phrasing I like to use is to draw a difference between *safe* and *sound*. The code is not safe because you have to use the `unsafe` keyword, no way around that. But it is sound because we check the length of the slice, as the compiler is trusting us to do. – durka42 Jan 11 '20 at 18:43
-
It definitely can be done in safe code; see Shepmaster's answer. It could also have been done in safe code prior to Rust 1.34, with a loop over the elements or with [copy_from_slice](https://doc.rust-lang.org/std/primitive.slice.html#method.copy_from_slice). – Daira Hopwood Aug 23 '21 at 15:58
-
As one of the Rust newcomers mentioned above, both the answer and the comments are extremely confusing to me. If someone wouldn't mind explaining, 1) why does this require an `unsafe` block when `.try_into().unwrap()` seems to work fine (maybe this is how it had to be done prior to Rust 1.34?), 2) since this answer checks that the slice is of length 3 before doing anything, how do comments about partial solutions due to slice length apply to this? – Codebling Jan 30 '23 at 19:21
-
@Codebling: 1. Yes, prior to stabilizing `TryInto` this was the only way, but nowadays it's definitely clearer to just call `.try_into()`. Don't include the `.unwrap()` unless you are 100% confident that the slice is the right length -- always better to check rather than crash the program. You can actually [see](https://doc.rust-lang.org/1.67.0/src/core/array/mod.rs.html#261) that the conversion is implemented using essentially the code in this answer. 2. Are you referring to @Zorf's comment? Besides the quibble about wording I *think* they were backing me up re: needing the length check. – durka42 Feb 01 '23 at 05:17
-
9
They arrayref crate implements this.
Here's an example, you can of course use it in different ways:
#[macro_use]
extern crate arrayref;
/// Get the first 3 elements of `bytes` as a reference to an array
/// **Panics** if `bytes` is too short.
fn first3(bytes: &[u8]) -> &[u8; 3] {
array_ref![bytes, 0, 3]
}

bluss
- 12,472
- 1
- 49
- 48