Как правильно инициализировать массив фиксированной длины?

У меня проблемы с инициализацией массива фиксированной длины. Все мои попытки до сих пор приводят к одному и тому же использованию возможно неинициализированной переменной: foo_array "ошибка:

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

impl Default for Foo {
    fn default() -> Foo { Foo{a:1, b:2} }
}

pub fn main() {
    let mut foo_array: [Foo; 10];

    // Do something here to in-place initialize foo_array?

    for f in foo_array.iter() {
        println!("{:?}", f);
    }
}
error[E0381]: use of possibly uninitialized variable: `foo_array`
  --> src/main.rs:13:14
   |
13 |     for f in foo_array.iter() {
   |              ^^^^^^^^^ use of possibly uninitialized `foo_array`

Я реализовал Default это черта, но Rust, похоже, не вызывает этого по умолчанию, как конструктор C++.

Как правильно инициализировать массив фиксированной длины? Я хотел бы сделать эффективную инициализацию на месте, а не какую-то копию.

Связанный: Почему свойство Copy необходимо для инициализации массива по умолчанию (struct valueed)?

Связанный: есть ли способ не инициализировать массивы дважды?

3 ответа

Решение

Безопасное, но несколько неэффективное решение:

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

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

Поскольку вы специально запрашиваете решение без копий:

use std::mem;
use std::ptr;

#[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 = unsafe {
        // Create an uninitialized array.
        let mut array: [Foo; 10] = mem::uninitialized();

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

            // Overwrite `element` without running the destructor of the old value.
            // Since Foo does not implement Copy, it is moved.
            ptr::write(element, foo)
        }

        array
    };

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

Самый простой способ - вывести Copy на свой тип и инициализируйте массив этим, скопировав элемент N раз:

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

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

Если вы хотите избежать копирования, есть несколько вариантов. Вы можете использовать трейт:

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

Однако это ограничено массивами до 32 элементов. С помощью дженериков const теперь стандартная библиотека может предоставлять Defaultдля всех массивов. Однако это было бы обратным несовместимым изменением по тонким причинам, над которыми сейчас работают.

А пока вы можете воспользоваться тем, что const значения также допускаются в выражениях повторения массива:

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

let mut foo_array = [FOO; 10];

Если вы в ночное время, вы можете использовать array::map:

      #![feature(array_map)]

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

Вы можете использовать arrayvec ящик:

Cargo.toml

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

[dependencies]
arrayvec = "0.3.20"

SRC /main.rs

extern crate arrayvec;

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!());
}
Другие вопросы по тегам