Initialize a large, fixed-size array with non-Copy

2019-01-08 01:34发布

问题:

I’m trying to initialize a fixed-size array of some nullable, non-copyable type, like an Option<Box<Thing>> for some kind of Thing. I’d like to pack two of them into a struct without any extra indirection. I’d like to write something like this:

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

But it doesn’t work because the [e; n] syntax requires that e implements Copy. Of course, I could expand it into SIZE Nones, but that can be unwieldy when SIZE is large. I don’t believe this can be done with a macro without an unnatural encoding of SIZE. Is there a good way to do it?

Yes, this is easy with unsafe; is there a way to do it without unsafe?

回答1:

You could use the Default trait to initialize the array with default values:

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

See this playground for a working example.



回答2:

I'm copying the answer by chris-morgan and adapting it to match the question better, to follow the recommendation by dbaupp downthread, and to match recent syntax changes:

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[..]);
}

Note the need to use unsafe here: The problem is that if the constructor function panic!s, this would lead to undefined behavior.



标签: rust