Reputation: 2130
I'm initializing an array using code called through FFI and thus I'm using an array if MaybeUninit
to represent that data. It looks something like this:
use std::mem::MaybeUninit;
#[allow(unused)]
fn init_with_ffi<T>(data: &mut [T]) {
todo!();
}
fn get_array<T, const D: usize>() -> [T; D] {
let mut my_array: [MaybeUninit<T>; D] = unsafe {
MaybeUninit::uninit().assume_init()
};
init_with_ffi(&mut my_array[..]);
unsafe {
*(&mut my_array as *mut [MaybeUninit<T>; D] as *mut [T; D])
}
}
This is similar to one of the examples presented in the docs for MaybeUninit but generic instead. I'm having to use raw pointers here since std::mem::transmute
does not work with arrays of a generic size.
However, I'm getting the following error:
error[E0508]: cannot move out of type `[T; D]`, a non-copy array
--> src/main.rs:14:9
|
14 | *(&mut my_array as *mut [MaybeUninit<T>; D] as *mut [T; D])
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| cannot move out of here
| move occurs because value has type `[T; D]`, which does not implement the `Copy` trait
This error message makes no sense to me. It would make sense if I was trying to copy a non-copy array or if I was trying to move ONE of the values out of a non-copy array. But I'm trying to move the entire array and my impression has always been that this should be possible, no?
Upvotes: 0
Views: 250
Reputation: 26599
Your code is effectively the same as:
let ptr: *mut [T;D] = &mut my_array as *mut [MaybeUninit<T>; D] as *mut [T; D];
*ptr
Which would attempt to copy, not move, the data out of the pointer - hence your issue
The usual solution, demonstrated in the Initializing an array element-by-element section in the MaybeUninit
docs, is using std::mem::transmute
instead, but currently it does not work with const generics.
Instead, you can use read
to copy the elements from the MaybeUninit<T>
array to a new T
array. In the general case, you would have to worry about duplicating a T
and dropping the same contents twice, but since MaybeUninit
doesn't call drop on its containing data when it itself is dropped, it should be safe. Otherwise you can use std::mem::forget
on the original array to force not calling the drop method.
Upvotes: 1