Creating a Vec<u8>
and then taking a slice is a perfectly fine way to do it if you need/want to create the resulting value dynamically (at runtime). You can't dynamically create an array, since the size has to be known at compile time, so you will have to create a buffer up front and then fill it.
You can use copy_from_slice()
to copy the slices into your array, but that only works if the slice is the same size as the destination. You can handle that by using split_at_mut()
to get each half as a mutable slice.
In this particular case, it's also possible to do it as a one-liner with some bitwise operations to get everything into the right place before calling to_be_bytes()
(Thanks to @Stargateur for the tip!)
fn concat_u16_copy(a: u16, b: u16) -> [u8; 4] {
let mut c = [0u8; 4];
let (left, right) = c.split_at_mut(2);
left.copy_from_slice(&a.to_be_bytes());
right.copy_from_slice(&b.to_be_bytes());
c
}
fn concat_u16_shift(a: u16, b: u16) -> [u8; 4] {
(((a as u32) << 16) | b as u32).to_be_bytes()
}
fn main() {
let n : u16 = 10;
let h : u16 = 16;
let b = concat_u16_copy(n, h);
println!("{b:?}");
let bb = concat_u16_shift(n, h);
println!("{bb:?}");
}
Playground
Interestingly, the compiler seems smart enough to turn both of those options into essentially the same code:
example::concat_u16_copy:
movzx eax, si
shl edi, 16
or eax, edi
bswap eax
ret
example::concat_u16_shift:
shl edi, 16
movzx eax, si
or eax, edi
bswap eax
ret
Godbolt