12

In C, I can write int foo[100] = { 7, 8 }; and I will get [7, 8, 0, 0, 0...].

This allows me to explicitly and concisely choose initial values for a contiguous group of elements at the beginning of the array, and the remainder will be initialised as if they had static storage duration (i.e. to the zero value of the appropriate type).

Is there an equivalent in Rust?

2 Answers 2

14

To the best of my knowledge, there is no such shortcut. You do have a few options, though.


The direct syntax

The direct syntax to initialize an array works with Copy types (integers are Copy):

let array = [0; 1024];

initializes an array of 1024 elements with all 0s.

Based on this, you can afterwards modify the array:

let array = {
    let mut array = [0; 1024];
    array[0] = 7;
    array[1] = 8;
    array
};

Note the trick of using a block expression to isolate the mutability to a smaller section of the code; we'll reuse it below.


The slice syntax

There is a shorter form, based on clone_from_slice.

let array = {
    let mut array = [0; 32];
    
    //  Override beginning of array.
    array[..2].clone_from_slice(&[7, 8]);

    array
};

The iterator syntax

There is also support to initialize an array from an iterator:

let array = {
    let mut array = [0; 1024];

    for (i, element) in array.iter_mut().enumerate().take(2) {
        *element = (i + 7);
    }

    array
};

And you can even (optionally) start from an uninitialized state, using an unsafe block:

#![feature(maybe_uninit_uninit_array)]

let array = {
    // Create an uninitialized array.
    let mut array: [MaybeUninit<i32>; 10] = MaybeUninit::uninit_array();

    let nonzero = 2;

    for (i, element) in array.iter_mut().enumerate().take(nonzero) {
        // Overwrite `element` without running the destructor of the old value.
        element.write(i + 7)
    }

    for element in array.iter_mut().skip(nonzero) {
        // Overwrite `element` without running the destructor of the old value.
        element.write(0)
    }

    //  Safety:
    //  -   All elements have been initialized.
    unsafe { MaybeUninit::array_assume_init(array) }
};
Sign up to request clarification or add additional context in comments.

1 Comment

@damd: Ohhh a lot changed indeed! I've updated the answer to (1) stop using mem::uninitialized() which is deprecated (and unsound) and (2) fix the clone_from_slice snippet => the "destination" slice needs to have the exact same length as the source slice, as you noted.
3

Here is macro

macro_rules! array {
    ($($v:expr),*) => (
        {
            let mut array = Default::default();
            {
                let mut e = <_ as ::std::convert::AsMut<[_]>>::as_mut(&mut array).iter_mut();
                $(*e.next().unwrap() = $v);*;
            }
            array
        }
    )
}

fn main() {
    let a: [usize; 5] = array!(7, 8);
    assert_eq!([7, 8, 0, 0, 0], a);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.