Rust 中 ZST/uninhabbited/one-representation 类型的 MaybeUninit 和初始化

MaybeUninit and initialization of ZST/uninhabbited/one-representation types in Rust

问题很简单,但我一直没能找到答案。下面这段代码是valid/safe在Rust中:

use core::mem::MaybeUninit;

// This is a ZST
#[derive(Debug)]
struct MyStruct;

// This is an uninhabited type
#[derive(Debug)]
enum MyEnum {}

#[derive(Debug)]
enum OneVariantEnum {
    Variant1,
}

fn main() {
    let s: MaybeUninit<MyStruct> = MaybeUninit::uninit();
    println!("s: {:?}", unsafe { s.assume_init() });

    let e: MaybeUninit<MyEnum> = MaybeUninit::uninit();
    println!("e: {:?}", unsafe { e.assume_init() });

    // and what about this?
    let o: MaybeUninit<OneVariantEnum> = MaybeUninit::uninit();
    println!("o: {:?}", unsafe { o.assume_init() });
}

MaybeUninit::assume_init() 的重点是将调用 MaybeUninit::uninit() 后初始化的内存转换为有效值。如果类型是零大小的,那么 MaybeUninit::uninit().assume_init() (大多数类型的 UB)实际上是有效的,因为根本没有内存可以初始化。如果它无效,那么 没有 方法可以使用 MaybeUninit 创建 ZST,并且文档中没有提到这样的限制。

This issue 包含一个讨论,顺便证实了这一点。

请注意,以上仅适用于 ZST,不适用于无人居住的类型,因此永远不允许构造 MyEnum,该示例是 UB。

以下似乎是正确的,因为 MyStruct 是 ZST:

let s: MaybeUninit<MyStruct> = MaybeUninit::uninit();
println!("s: {:?}", unsafe { s.assume_init() });

然而,构造一个无人居住类型的值总是 UB,所以以下是不正确的:

let e: MaybeUninit<MyEnum> = MaybeUninit::uninit();
println!("e: {:?}", unsafe { e.assume_init() });

在调试模式下,Rust 可能 捕捉到这个并用

恐慌

thread 'main' panicked at 'attempted to instantiate uninhabited type MyEnum'


至于OneVariantEnum,是ZST,所以和MyStruct类似,以下不涉及UB:

let o: MaybeUninit<OneVariantEnum> = MaybeUninit::uninit();
println!("o: {:?}", unsafe { o.assume_init() });