MaybeUninit и массивы
// Copyright 2026 Google LLC
// SPDX-License-Identifier: Apache-2.0
use std::mem::MaybeUninit;
use std::ptr;
fn main() {
let input = b"RUST";
let mut buf = [const { MaybeUninit::<u8>::uninit() }; 2048];
// Инициализируем элементы, записывая значения в память
for (i, input_byte) in input.iter().enumerate() {
unsafe {
let dst = buf.as_mut_ptr().add(i);
ptr::write((*dst).as_mut_ptr(), *input_byte);
}
}
// Когда часть массива инициализирована, можно
// использовать unsafe, чтобы выделить её
let ptr_to_init_subslice = buf.as_ptr() as *const u8;
let init =
unsafe { std::slice::from_raw_parts(ptr_to_init_subslice, input.len()) };
let text = std::str::from_utf8(init).unwrap();
println!("{text}");
// Инициализированные элементы нужно освобождать вручную
for element in &mut buf[0..input.len()] {
unsafe {
element.assume_init_drop();
}
}
}
Чтобы создать массив неинициализированной памяти, можно использовать конструктор ::uninit() в контексте const.
Инициализируйте значения обычным способом через ptr::write.
.assume_init() для массивов работает не так просто. Он требует, чтобы каждое значение было инициализировано, а это может не выполняться при повторном использовании буфера. В этом примере указатель используется, чтобы выделить инициализированные байты и создать строковый срез.
При создании подсреза частично инициализированного массива будьте внимательны с владением и правильной реализацией drop. Напоминание: MaybeUninit<T> не вызывает drop для своего T.
MaybeUninit<[u8;2048]> отличается от [MaybeUninit::<u8>; 2048]. Это разница между массивом неинициализированной памяти и массивом, который содержит неинициализированные элементы.
MaybeUninit<[u8;2048]>— «всё или ничего». Либо вы полностью инициализируете весь массив и затем вызываетеassume_init, либо должны оставить его какMaybeUninit<[u8; 2048]>и не обращаться к нему как к[u8; 2048].[MaybeUninit<u8>; 2048]позволяет инициализировать элементы по одному, затем взять подсрез только из инициализированного префикса и обращаться с ним как с[u8]черезstd::slice::from_raw_parts.slice_assume_init_refбезопасен, только если каждый элемент среза инициализирован. В этом примере мы передаём&buf[..input.len()]только после записи ровно этих байтов.- Если
Tтребует drop, для инициализированных элементов нужно вручную вызватьassume_init_drop(). Если это пропустить, возникнет утечка памяти. Однако вызов этого метода для неинициализированного элемента — неопределённое поведение.