Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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(). Если это пропустить, возникнет утечка памяти. Однако вызов этого метода для неинициализированного элемента — неопределённое поведение.