The compiler, in general, assumes that a variable is properly initialized
according to the requirements of the variable's type. For example, a variable of
reference type must be aligned and non-NULL. This is an invariant that must
always be upheld, even in unsafe code. As a consequence, zero-initializing a
variable of reference type causes instantaneous undefined behavior,
no matter whether that reference ever gets used to access memory:

Moreover, uninitialized memory is special in that the compiler knows that
it does not have a fixed value. This makes it undefined behavior to have
uninitialized data in a variable even if that variable has an integer type,
which otherwise can hold any fixed bit pattern:

(Notice that the rules around uninitialized integers are not finalized yet, but
until they are, it is advisable to avoid them.)

On top of that, remember that most types have additional invariants beyond merely
being considered initialized at the type level. For example, a 1-initialized Vec<T>
is considered initialized (under the current implementation; this does not constitute
a stable guarantee) because the only requirement the compiler knows about it
is that the data pointer must be non-null. Creating such a Vec<T> does not cause
immediate undefined behavior, but will cause undefined behavior with most
safe operations (including dropping it).

MaybeUninit<T> serves to enable unsafe code to deal with uninitialized data.
It is a signal to the compiler indicating that the data here might not
be initialized:

usestd::mem::MaybeUninit;
// Create an explicitly uninitialized reference. The compiler knows that data inside// a `MaybeUninit<T>` may be invalid, and hence this is not UB:letmutx=MaybeUninit::<&i32>::uninit();
// Set it to a valid value.unsafe { x.as_mut_ptr().write(&0); }
// Extract the initialized data -- this is only allowed *after* properly// initializing `x`!letx=unsafe { x.assume_init() };

You can use MaybeUninit<T> to implement "out-pointers": instead of returning data
from a function, pass it a pointer to some (uninitialized) memory to put the
result into. This can be useful when it is important for the caller to control
how the memory the result is stored in gets allocated, and you want to avoid
unnecessary moves.

MaybeUninit<T> can be used to initialize a large array element-by-element:

usestd::mem::{self, MaybeUninit};
letdata= {
// Create an uninitialized array of `MaybeUninit`. The `assume_init` is// safe because the type we are claiming to have initialized here is a// bunch of `MaybeUninit`s, which do not require initialization.letmutdata: [MaybeUninit<Vec<u32>>; 1000] =unsafe {
MaybeUninit::uninit().assume_init()
};
// Dropping a `MaybeUninit` does nothing. Thus using raw pointer// assignment instead of `ptr::write` does not cause the old// uninitialized value to be dropped. Also if there is a panic during// this loop, we have a memory leak, but there is no memory safety// issue.forelemin&mutdata[..] {
*elem=MaybeUninit::new(vec![42]);
}
// Everything is initialized. Transmute the array to the// initialized type.unsafe { mem::transmute::<_, [Vec<u32>; 1000]>(data) }
};
assert_eq!(&data[0], &[42]);

You can also work with partially initialized arrays, which could
be found in low-level datastructures.

usestd::mem::MaybeUninit;
usestd::ptr;
// Create an uninitialized array of `MaybeUninit`. The `assume_init` is// safe because the type we are claiming to have initialized here is a// bunch of `MaybeUninit`s, which do not require initialization.letmutdata: [MaybeUninit<String>; 1000] =unsafe { MaybeUninit::uninit().assume_init() };
// Count the number of elements we have assigned.letmutdata_len: usize=0;
forelemin&mutdata[0..500] {
*elem=MaybeUninit::new(String::from("hello"));
data_len+=1;
}
// For each item in the array, drop if we allocated it.forelemin&mutdata[0..data_len] {
unsafe { ptr::drop_in_place(elem.as_mut_ptr()); }
}

There is currently no supported way to create a raw pointer or reference
to a field of a struct inside MaybeUninit<Struct>. That means it is not possible
to create a struct by calling MaybeUninit::uninit::<Struct>() and then writing
to its fields.

However remember that a type containing a MaybeUninit<T> is not necessarily the same
layout; Rust does not in general guarantee that the fields of a Foo<T> have the same order as
a Foo<U> even if T and U have the same size and alignment. Furthermore because any bit
value is valid for a MaybeUninit<T> the compiler can't apply non-zero/niche-filling
optimizations, potentially resulting in a larger size:

While MaybeUninit is #[repr(transparent)] (indicating it guarantees the same size,
alignment, and ABI as T), this does not change any of the previous caveats. Option<T> and
Option<MaybeUninit<T>> may still have different sizes, and types containing a field of type
T may be laid out (and sized) differently than if that field were MaybeUninit<T>.
MaybeUninit is a union type, and #[repr(transparent)] on unions is unstable (see the
tracking issue). Over time, the exact
guarantees of #[repr(transparent)] on unions may evolve, and MaybeUninit may or may not
remain #[repr(transparent)]. That said, MaybeUninit<T> will always guarantee that it has
the same size, alignment, and ABI as T; it's just that the way MaybeUninit implements that
guarantee may evolve.

🔬 This is a nightly-only experimental API. (maybe_uninit_uninit_array)

Create a new array of MaybeUninit<T> items, in an uninitialized state.

Note: in a future Rust version this method may become unnecessary
when array literal syntax allows
repeating const expressions.
The example below could then use let mut buf = [MaybeUninit::<u8>::uninit(); 32];.

Creates a new MaybeUninit<T> in an uninitialized state, with the memory being
filled with 0 bytes. It depends on T whether that already makes for
proper initialization. For example, MaybeUninit<usize>::zeroed() is initialized,
but MaybeUninit<&'static i32>::zeroed() is not because references must not
be null.

Note that dropping a MaybeUninit<T> will never call T's drop code.
It is your responsibility to make sure T gets dropped if it got initialized.

Incorrect usage of this function: initializing a struct with zero, where some fields
cannot hold 0 as a valid value.

usestd::mem::MaybeUninit;
enumNotZero { One=1, Two=2 };
letx=MaybeUninit::<(u8, NotZero)>::zeroed();
letx=unsafe { x.assume_init() };
// Inside a pair, we create a `NotZero` that does not have a valid discriminant.// This is undefined behavior.

Sets the value of the MaybeUninit<T>. This overwrites any previous value
without dropping it, so be careful not to use this twice unless you want to
skip running the destructor. For your convenience, this also returns a mutable
reference to the (now safely initialized) contents of self.

Gets a pointer to the contained value. Reading from this pointer or turning it
into a reference is undefined behavior unless the MaybeUninit<T> is initialized.
Writing to memory that this pointer (non-transitively) points to is undefined behavior
(except inside an UnsafeCell<T>).

It is up to the caller to guarantee that the MaybeUninit<T> really is in an initialized
state. Calling this when the content is not yet fully initialized causes immediate undefined
behavior. The type-level documentation contains more information about
this initialization invariant.

On top of that, remember that most types have additional invariants beyond merely
being considered initialized at the type level. For example, a 1-initialized [Vec<T>]
is considered initialized (under the current implementation; this does not constitute
a stable guarantee) because the only requirement the compiler knows about it
is that the data pointer must be non-null. Creating such a Vec<T> does not cause
immediate undefined behavior, but will cause undefined behavior with most
safe operations (including dropping it).

It is up to the caller to guarantee that the MaybeUninit<T> really is in an initialized
state. Calling this when the content is not yet fully initialized causes undefined
behavior. The type-level documentation contains more information about
this initialization invariant.

Moreover, this leaves a copy of the same data behind in the MaybeUninit<T>. When using
multiple copies of the data (by calling read multiple times, or first
calling read and then assume_init), it is your responsibility
to ensure that that data may indeed be duplicated.

#![feature(maybe_uninit_extra)]usestd::mem::MaybeUninit;
letmutx=MaybeUninit::<Option<Vec<u32>>>::uninit();
x.write(Some(vec![0,1,2]));
letx1=unsafe { x.read() };
letx2=unsafe { x.read() };
// We now created two copies of the same vector, leading to a double-free when// they both get dropped!

#![feature(maybe_uninit_ref)]usestd::mem::MaybeUninit;
letx=MaybeUninit::<Vec<u32>>::uninit();
letx_vec: &Vec<u32>=unsafe { x.get_ref() };
// We have created a reference to an uninitialized vector! This is undefined behavior.

Calling this when the content is not yet fully initialized causes undefined
behavior: it is up to the caller to guarantee that the MaybeUninit<T> really
is in an initialized state. For instance, .get_mut() cannot be used to
initialize a MaybeUninit.

#![feature(maybe_uninit_ref)]usestd::mem::MaybeUninit;
extern"C" {
/// Initializes *all* the bytes of the input buffer.fninitialize_buffer(buf: *mut [u8; 2048]);
}
letmutbuf=MaybeUninit::<[u8; 2048]>::uninit();
// Initialize `buf`:unsafe { initialize_buffer(buf.as_mut_ptr()); }
// Now we know that `buf` has been initialized, so we could `.assume_init()` it.// However, using `.assume_init()` may trigger a `memcpy` of the 2048 bytes.// To assert our buffer has been initialized without copying it, we upgrade// the `&mut MaybeUninit<[u8; 2048]>` to a `&mut [u8; 2048]`:letbuf: &mut [u8; 2048] =unsafe {
// Safety: `buf` has been initialized.buf.get_mut()
};
// Now we can use `buf` as a normal slice:buf.sort_unstable();
assert!(
buf.windows(2).all(|pair|pair[0] <=pair[1]),
"buffer is sorted",
);

#![feature(maybe_uninit_ref)]usestd::mem::MaybeUninit;
letmutb=MaybeUninit::<bool>::uninit();
unsafe {
*b.get_mut() =true;
// We have created a (mutable) reference to an uninitialized `bool`!// This is undefined behavior.
}