Type annotation required for array

Trying to build a big array b from a smaller one a, where the rest of items in the array are zeros, to be manipulated later on.

I'm looking for a way better than using a loop, so thought to make it as below:

    const z: usize = 4;
    let mut a: [u8; 3] = [1, 2, 3];
    let mut b: [u8; z];
    b = [Default::default(); z];
    // b.clone_from_slice(&a); // failed as a.len() != b.len()

    a.iter().zip(&b).map(|(x, y)| y = x).collect();

But I got the below error:

error[E0283]: type annotations required: cannot resolve `_: std::iter::FromIterator<()>`
  --> cell.rs:15:42
   |
15 |     a.iter().zip(&b).map(|(x, y)| y = x).collect();
   |                                          ^^^^^^^

error: aborting due to previous error

I tried:

&a.iter().zip(&b).map(|(x, y)| y = x).collect::<u8>();

But got:

error[E0277]: a collection of type `u8` cannot be built from an iterator over elements of type `()`
  --> cell.rs:15:43
   |
15 |     &a.iter().zip(&b).map(|(x, y)| y = x).collect::<u8>();
   |                                           ^^^^^^^ a collection of type `u8` cannot be built from `std::iter::Iterator<Item=()>`
   |
   = help: the trait `std::iter::FromIterator<()>` is not implemented for `u8`

Not sure if zipping the 2 arrays is a correct or wrong way, appreciate to help me fix this error, and your comments are welcomed.

The actual objective of my problem is to build expandable array not vec! as I want to work in real multi-dimensional array, considering array size in rust is fixed, I'm looking for a work around.

"Expandable array" is a Vec - or any other struct with manual memory management inside it, but not the array. What's wrong with Vec?

I want to work in real multi-dimensional array, I updated my question by adding this note.

I'm not sure what you want but here's my solution.

fn main() {
    const Z: usize = 4;
    let a: [u8; 3] = [1, 2, 3];
    let b = expand(&a[..], Z);
    dbg!(b);
}

fn expand<T: Clone + Copy + Default>(array: &[T], n: usize) -> Vec<T> {
    let r = (n as isize - array.len() as isize).max(0) as usize;
    let z = vec![<T as Default>::default()];
    let z = z.iter().cloned().cycle().take(r);
    array.iter().cloned().chain(z).collect()
}

Thanks, the return is a vec!, I tuned the code as below to return an array

fn main() {
    const Z: usize = 4;
    let a: [u8; 3] = [1, 2, 3];
    let b = expand(&a[..], Z);
    println!("{:#?}", b);
    dbg!(b);
}

fn expand<T: Clone + Copy + Default>(array: &[T], n: usize) -> [T; 4] {
    let r = (n as isize - array.len() as isize).max(0) as usize;
    let z = vec![<T as Default>::default()];
    let z = z.iter().cloned().cycle().take(r);
    let barry: Vec<T> = array.iter().cloned().chain(z).collect();
    
    let mut array = [<T as Default>::default(); 4];
    for (&x, p) in barry.iter().zip(array.iter_mut()) {
        *p = x;
    }
    array
}

I was able to solve it by:

  1. replacing the collect by count which does not need annotation
  2. using b.iter_mut() instead of &b

So the solution is:

// Replacing:
a.iter().zip(&b).map(|(x, y)| y = x).collect();
// By:
a.iter().zip(b.iter_mut()).map(|(&x, y)| *y = x).count();
b[..a.len()].copy_from_slice(&a);

It uses memcpy(3) underneath, which should be faster than byte-by-byte copy.

3 Likes