What is the proper way to initialize a fixed length array?

The safe but somewhat inefficient solution:

#[derive(Copy, Clone, Debug)]
struct Foo {
    a: u32,
    b: u32,
}

fn main() {
    let mut foo_array = [Foo { a: 10, b: 10 }; 10];
}

Since you're specifically asking for a solution without copies:

use std::mem::MaybeUninit;

#[derive(Debug)]
struct Foo {
    a: u32,
    b: u32,
}

// We're just implementing Drop to prove there are no unnecessary copies.
impl Drop for Foo {
    fn drop(&mut self) {
        println!("Destructor running for a Foo");
    }
}

pub fn main() {
    let array = {
        // Create an array of uninitialized values.
        let mut array: [MaybeUninit<Foo>; 10] = unsafe { MaybeUninit::uninit().assume_init() };

        for (i, element) in array.iter_mut().enumerate() {
            let foo = Foo { a: i as u32, b: 0 };
            *element = MaybeUninit::new(foo);
        }

        unsafe { std::mem::transmute::<_, [Foo; 10]>(array) }
    };

    for element in array.iter() {
        println!("{:?}", element);
    }
}

This is recommended by the documentation of MaybeUninit.


You can use the arrayvec crate:

Cargo.toml

[package]
name = "initialize_array"
version = "0.1.0"
authors = ["author"]
edition = "2018"

[dependencies]
arrayvec = "0.4.10"

src/main.rs

use arrayvec::ArrayVec; 
use std::iter;

#[derive(Clone)]
struct Foo {
    a: u32,
    b: u32,
}

fn main() {
    let foo_array: [Foo; 10] = iter::repeat(Foo { a: 10, b: 10 })
        .collect::<ArrayVec<_>>()
        .into_inner()
        .unwrap_or_else(|_| unreachable!());
}

The easiest way is to derive Copy on your type and initialize the array with that, copying the element N times:

#[derive(Copy)]
struct Foo {
    a: u32,
    b: u32,
}

let mut foo_array = [Foo { a: 1, b: 2 }; 10];

If you want to avoid copying, there are a couple options. You can use the Default trait:

let mut foo_array: [Foo; 10] = Default::default();

However, this is limited to arrays up to 32 elements. With const generics, it is now possible for the standard library to provide Default for all arrays. However, this would be a backward incompatible change for subtle reasons that are being worked on.

For now, you can take advantage of the fact that const values are also allowed in array repetition expressions:

const FOO: Foo = Foo { a: 1, b: 2 };

let mut foo_array = [FOO; 10];

If you're on nightly, you can use array::map:

#![feature(array_map)]

let mut foo_array = [(); 10].map(|_| Foo::default())

Tags:

Arrays

Rust