Build array from part of another array

Hi!

let ar1: [u8; 3] = [1,2,3];
let mut r: [u8; 2] = Default::default();
r.copy_from_slice(&v[..2]);

Is it possible to build new array without default and copy?
Something like

let r = [u8; 2]::from_slice(&v[..2]);

There are some implementations of TryFrom for slices and arrays.

When the type in the array is Copy you can convert a slice directly into an array. For non-copy types, you can convert a slice to a reference to an array.

Playground

fn main() {
    let slice: &[u8] = &[1, 2, 3, 4];
    let arr = <[u8; 4]>::try_from(slice);

    let strings: &[String] = &["one".into(), "two".into()];
    let string_arr = <&[String; 2]>::try_from(strings);

    println!("{arr:?}\n{string_arr:?}");
}

Since there’s a blanket impl of TryInto on TryFrom you can also rephrase it like

fn main() {
    let slice: &[u8] = &[1, 2, 3, 4];
    let arr: Result<[u8; 4], _> = slice.try_into();

    let strings: &[String] = &["one".into(), "two".into()];
    let string_arr: Result<&[String; 2], _> = strings.try_into();

    println!("{arr:?}\n{string_arr:?}");
}

Which may be easier in some contexts

2 Likes

Looks easier but i'm surprised of rust cant to create array with copy of another without "try..."

Well a slice doesn't have a statically known size, so if the slice is too short it's really important that it not just silently hand you uninitialized memory. Hence the Result.

These implementations actually require that the size of the slice is exactly the same to help catch bugs more easily. (e.g. let arr: Result<[u8; 2], _> = slice.try_into(); returns an error)

arr[0..2]
Doesn't statically known size?

Yes, because arr[a..b] does not require the endpoints a and b to be const. Rust cannot infer anything about the size of a slice during compilation. Even if you use int literals, which are const.

It's statically known enough for the optimizer to remove code which handles incorrect size, but it's not statically known enough to have Sized type.

It's still !Sized, just its current size happens to always be 3.

1 Like

Here's one way:

let ar1: [u8; 3] = [1,2,3];
let r: [u8; 2] = std::array::from_fn(|i| ar1[i]);

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c5c45c680e0b851a7ad4568188f9d2b1

Compiles down to essentially nothing, too: https://rust.godbolt.org/z/9znjozM38.

1 Like