Подтвердить что ты не робот

Инициализировать большой массив фиксированного размера с типами без копирования

Я пытаюсь инициализировать массив фиксированного размера некоторого типа NULL, не скопируемого типа, как Option<Box<Thing>> для некоторого Thing. Id нравится упаковывать два из них в структуру без какого-либо дополнительного обращения. Id нравится писать что-то вроде этого:

let array: [Option<Box<Thing>>; SIZE] = [None; SIZE];

Но это не работает, потому что синтаксис [e; n] требует, чтобы e реализовал Copy. Конечно, я мог бы расширить его на SIZE None s, но это может быть громоздким, когда SIZE велико. Я не верю, что это можно сделать с помощью макроса без неестественного кодирования SIZE. Есть ли хороший способ сделать это?

Да, это легко с unsafe; есть ли способ сделать это без unsafe?

4b9b3361

Ответ 1

Вы можете использовать черту Default для инициализации массива значениями по умолчанию:

let array: [Option<Box<Thing>>; SIZE] = Default::default();

Смотрите эту площадку для рабочего примера.

Ответ 2

Я копирую ответ chris-morgan и адаптируя его для лучшего ответа на вопрос, чтобы следовать рекомендации dbupp downthread, и соответствовать последним синтаксическим изменениям:

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

#[derive(Debug)]
struct Thing {
    number: usize,
}

macro_rules! make_array {
    ($n:expr, $constructor:expr) => {{
        let mut items: [_; $n] = mem::uninitialized();
        for (i, place) in items.iter_mut().enumerate() {
            ptr::write(place, $constructor(i));
        }
        items
    }}
}

const SIZE: usize = 50;

fn main() {
    let items = unsafe { make_array!(SIZE, |i| Box::new(Some(Thing { number: i }))) };
    println!("{:?}", &items[..]);
}

Обратите внимание на необходимость использования unsafe здесь: проблема в том, что если функция конструктора panic! s, это приведет к поведению undefined.

Ответ 3

Это простой ответ: просто наберите все значения:

struct Thing;
const SIZE: usize = 5;

fn main() {
    let array: [Option<Box<Thing>>; SIZE] = [None, None, None, None, None];
}

Вы также можете использовать скрипт сборки, чтобы сгенерировать этот код для вас.