PhantomPinned 成员会使我的结构具有固定的内存地址吗?

Will a PhantomPinned member make my struct have a fixed memory address?

我正在编写与 C API 通信的 Rust 代码,我需要某个结构来拥有固定的内存地址。到目前为止,我发现:

如果我理解正确,PhantomPinned 将是最容易使用的:将它作为成员将使我的结构自动具有固定的内存地址。这是正确的吗?

你需要的是Pin。它是一个指针,可以防止您的对象被移动。

pin_mut!() 只是一个宏,可以帮助您创建一个 Pin 实例,无需堆分配或 unsafe 代码。

PhantomPinned 还有一个相关的目标。默认情况下,您的类型将实现 Unpin 特征(除非它包含不实现 Unpin 的类型,但大多数类型都实现)。这是有问题的,因为对于实现 Unpin 的类型,Pin 没有效果:它不会阻止您移动它们。这是因为大多数类型不需要固定的内存地址。想想 i32,例如:即使你创建了 Pin<&mut i32>,你也可以移动它,因为 i32 实现了 Unpin,因为即使你移动它也没有什么坏处发生,并且不会验证任何数据。

因此,要使 Pin 有效,您需要 un-impl Unpin。这是通过包含一个不实现 Unpin 本身作为字段的字段,或者具有负面影响(参见 )来完成的:

impl !Unpin for MyType {}

不幸的是,负面影响是不稳定的。相反,标准库提供了 PhantomPinned 类型,它是无成本的(一个 ZST),但没有实现 Unpin (它有一个负面影响,因为标准库被允许使用不稳定的特性它可以做到)。现在,当您的类型包含它时,它也会变成 !Unpin

综上所述,您需要在结构中包含 PhantomPinned,这样它就不会是 Unpin,并且您需要将它包裹在 Pin 中,这样它就无法移动。

Rust 中唯一不可移动的值是 Pin<T> 中的值,并且仅当 T 未实现 Unpin.

T 可能是引用或某些智能指针类型,如 BoxArc,但需要 Pin 来指定该值可能不会移动。

Unpin 是为不关心它们是否被移动(即使它们被固定)的类型实现的特征。它是为所有成员都实现 Unpin 的所有类型自动实现的标记特征。 PhantomPinned 是一个简单的零大小类型,它 实现 Unpin,因此可以将它添加到结构或枚举中以使其不会自动实现 Unpin.

请注意,Unpin 仅与 Pin 包装值相关 - Pin 之外的值仍然可以移动。需要不移动值的操作应该采用 Pin<&mut T> 而不是 &mut T.

pin_mut 是一个用于将堆栈值转换为固定指针的宏。这只是 known-safe 案例的一种便利,并没有真正发挥 Pin 的作用。


所以对于你的情况,听起来你的结构应该有一个 PhantomPinned 成员,并且它的所有操作都应该采用 pin-wrapped 引用。