我正在尝试使用 Box::new_uninit_in 和 ptr::addr_of_mut! 初始化一个枚举变体,在我的例子中它是一个结构体。然而,我正在努力进入正确的领域。有人可以帮我解决这个问题吗?
#![feature(allocator_api)]
use std::alloc::Allocator;
use std::mem::MaybeUninit;
use core::ptr::{self, NonNull};
fn main() {}
enum Node<K, V> {
LeafNode {
size: u16,
keys: [MaybeUninit<K>; 10],
vals: [MaybeUninit<V>; 10],
prev: Option<NonNull<Node<K, V>>>,
next: Option<NonNull<Node<K, V>>>,
},
InternalNode {
size: u16,
keys: [MaybeUninit<K>; 10],
vals: [MaybeUninit<NonNull<Node<K, V>>>; 11],
},
}
impl<K, V> Node<K, V> {
unsafe fn init(this: *mut Self) {
unsafe {
// 1. How do I access the fields of the struct within the enum?
// 2. How can I initialize the enum as either the LeafNode variant or the InternalNode variant?
ptr::addr_of_mut!((*this).size).write(0);
}
}
fn new<A: Allocator + Clone>(alloc: A) -> Box<Self, A> {
unsafe {
let mut node = Box::new_uninit_in(alloc);
Node::init(node.as_mut_ptr());
node.assume_init()
}
}
}
我尝试使用
node
将 Node::LeafNode
转换为 node as Node::LeafNode
,但 Rust 不允许我这样做。也许我做错了。
初始化非常简单:
this.write(Self::LeafNode {
size: 0,
keys: MaybeUninit::uninit_array(),
vals: MaybeUninit::uninit_array(),
prev: None,
next: None,
});
this.write(Self::InternalNode {
size: 0,
keys: MaybeUninit::uninit_array(),
vals: MaybeUninit::uninit_array(),
});
对于访问和变异,您将需要一个参考。您无法(在稳定版上)手动获取枚举内字段的偏移量。
不过,这并没有那么糟糕:如果您已经初始化了变体,通常可以创建对它的引用。如果您遇到锯齿问题,请考虑
UnsafeCell
。
如果您确实需要访问字段,您可以使用
#[repr(int)]
或#[repr(C)]
枚举,它们的布局已定义,您可以计算它。
offset_of!()
(宏是稳定的,但它的部分行为仍然不稳定):
this.byte_add(std::mem::offset_of!(Self, LeafNode.size))
.cast::<u16>()
.write(0);
this.byte_add(std::mem::offset_of!(Self, LeafNode.prev))
.cast::<Option<NonNull<Node<K, V>>>>()
.write(None);
this.byte_add(std::mem::offset_of!(Self, LeafNode.next))
.cast::<Option<NonNull<Node<K, V>>>>()
.write(None);
在大多数情况下,这种方法相对于简单方法应该没有优势(当然,除了它更冗长并且让你看起来更聪明)。更糟糕的是,即使使用
offset_of!()
,您也无法初始化 判别式 ,因此您将永远无法创建对枚举的引用或对其进行模式匹配。