Как я могу/должен получить &[MaybeUninit<T>] от &[T]?
Интуитивно мне должно быть разрешено рассматривать инициализированную память как возможно неинициализированную, но интуиция и unsafe не всегда хорошо сочетаются... Поскольку MaybeUninit<T> гарантированно будет иметь тот же размер и выравнивание, что и T, должно быть безопасно вставлять transmute a &[T] в а &[MaybeUninit<T>]?
Опять же, текущая реализация MaybeUninit::new(val) делает больше, чем просто трансмутацию, она добавляет обертку ManuallyDrop::new(val). Означает ли это, что если бы я реализовал slice_as_maybeuninit посредством трансмутации, я столкнулся бы с проблемами, связанными с тем, что деструкторы не запускаются? Это не unsafe, но все же достаточно нежелательно, чтобы ограничивать такую функцию фрагментами данных, которые реализуют Copy (т. е. которые не реализуют Drop).
Чтобы сделать мой вопрос(ы) более точным:
fn slice_as_maybeuninit<'a, T>(s: &'a [T]) -> &'a [MaybeUninit<T>], если вообще?fn slice_as_maybeuninit<'a, T: Copy>(s: &'a [T]) -> &'a [MaybeUninit<T>]? // обратите внимание на границу T: Copystd::mem::MaybeUninit не предоставляет мне эти операции?@BallpointBen Вариант использования работает с функцией, которая работает с фрагментом элементов MaybeUninitialized. Я не могу изменить эту функцию, но мне нужна ее функциональность для «нормального» фрагмента данных. Являются ли варианты ввода этой функции ошибочными? Может быть. Изменит ли ошибочность вопрос на гипотетический? К сожалению нет.
Чтобы ответить на ваш бонусный вопрос. Многие API, связанные с неинициализированной памятью, в настоящее время нестабильны. Вполне возможно, что такое преобразование будет добавлено в будущем, хотя стабилизация текущих API, вероятно, будет иметь более высокий приоритет.

Как мне реализовать
fn slice_as_maybeuninit<'a, T>(s: &'a [T]) -> &'a [MaybeUninit<T>], если вообще?
Не использовать трансмутацию (я не уверен, что это неправильно, поскольку расположение срезов не гарантируется, но это определенно не очень хорошая практика). Однако простой приведение подойдет:
fn slice_as_maybeuninit<'a, T>(s: &'a [T]) -> &'a [MaybeUninit<T>] {
// SAFETY:
// - `MaybeUninit<T>` is guaranteed to have the same layout as `T`.
// - Slices with compatible elements layout have compatible layout,
// since slices are have the same layout as the backing array
// and array lay all elements consecutively.
// - It is always safe to treat initialized values as possibly-initialized.
unsafe { &*(s as *const [T] as *const [MaybeUninit<T>]) }
}
bytemuck также может здесь помочь, если вы сможете реализовать черты NoUninit и AnyBitPattern для T. Просто используйте must_cast_slice().
Однако важно отметить, что нецелесообразно реализовывать преобразование &mut [T] -> &mut [MaybeUninit<T>] (или &UnsafeCell<[T]> -> &UnsafeCell<[MaybeUninit<T>]> или с любым другим внутренним контейнером изменяемости), поскольку это позволит пользователю выполнить преобразование, поместите MaybeUninit::uninit() здесь, затем прочитайте его как инициализированный из исходной ссылки.
Как мне реализовать
fn slice_as_maybeuninit<'a, T: Copy>(s: &'a [T]) -> &'a [MaybeUninit<T>]? // обратите внимание на границуT: Copy
Я думаю, вызвав предыдущую функцию?
Бонус: Почему
std::mem::MaybeUninitне предоставляет мне эти операции?
Он не предоставляет много возможных операций. Вы можете предложить это, или, может быть, Проект «Безопасное трансмутирование» в конечном итоге сделает это возможным.
Трансмутация из [T] в [MaybeUninit<T>] совершенно безопасна. Документы по его макету:
MaybeUninit<T>гарантированно будет иметь тот же размер, выравнивание и ABI, что иT:
Однако вы хотите использовать from_raw_parts для создания нового среза вместо просто transmute.
fn slice_as_maybeuninit<T>(s: &[T]) -> &[MaybeUninit<T>] {
unsafe { std::slice::from_raw_parts(s.as_ptr() as *const MaybeUninit<T>, s.len()) }
}
[Смогу ли я] столкнуться с проблемами из-за того, что деструкторы не запускаются?
Нет. В других обстоятельствах вы могли бы MaybeUninit ослабить критерии инициализации, чтобы он не удалял свое содержимое, поскольку сам по себе не знает, инициализировано ли его содержимое. Однако вы преобразуете только &[T], который является лишь ссылкой на содержимое; поэтому он все равно не будет пытаться удалить значения.
Copy не требуется, поскольку значения T не создаются.
Это гипотетический вопрос, или у вас действительно есть законные основания забывать, что инициализированная память инициализируется?