How to initialize a const generic array?

3k Views Asked by At

I am trying to learn more about const generics and how they can apply to some grid algorithms in any dimensions. Below is a snippet - how can I create an array of the size of a const generic parameter?

type Point<const N: usize> = [i32; N];

fn new_point<const N: usize>(x: i32, y: i32) -> Point<N> {
    [x, y]
}

fn main() {
    let point: Point<2> = new_point(1, 2);
    println!("Point: {:?}", point)
}

The above results in a compiler error:

error[E0308]: mismatched types
 --> src/main.rs:4:5
  |
3 | fn new_point<const N: usize>(x: i32, y: i32) -> Point<N> {
  |                                                 -------- expected `[i32; N]` because of return type
4 |     [x, y]
  |     ^^^^^^ expected `N`, found `2_usize`
  |
  = note: expected array `[i32; N]`
             found array `[i32; 2]`

Note that I am not looking for a solution using Vec<N>. How can I initialize this generic array with some values?

1

There are 1 best solutions below

1
On

Here are some ways to construct an array of arbitrary length.

  • You can use std::array::from_fn which will allow constructing an array of any size from a function computing its elements:

    /// Constructs an array with the first two elements being x and y.
    fn new_point<const N: usize>(x: i32, y: i32) -> Point<N> {
        std::array::from_fn(|i| {
            match i {
                0 => x,
                1 => y,
                _ => 0,
            }
        })
    }
    
  • You can construct an array with copies of a single value:

    [0; N]
    
    // or
    [foo(); N]
    
  • You can construct an array and then mutate it:

    fn new_point<const N: usize>(x: i32, y: i32) -> Point<N> {
        let mut array = [0; N];
        if N > 0 {
            array[0] = x;
        }
        if N > 1 {
            array[1] = y;
        }
        array
    }
    
  • You can construct an array by mapping from another array (this used to be done as a workaround for lack of from_fn()):

    let mut i = 0;
    [(); N].map(|()| {
        i += 1;
        i
    }]
    
  • You can construct an array by using .try_into() to convert a slice or vector; the conversion will fail if the slice or vector is not the correct length. See the list of implementors of TryFrom, and look for the ones that say ... for [T; N].