我正在编写与C API通信的Rust代码,我需要一个特定的 struct 来拥有一个固定的内存地址.到目前为止,我发现:
-
Pin
个指针; -
pin_mut
个宏以固定在堆栈上; -
PhantomPinned
,我不清楚.
如果我理解正确,PhantomPinned
将是最容易使用的:将其作为成员将使我的 struct 自动拥有固定的内存地址.对吗?
我正在编写与C API通信的Rust代码,我需要一个特定的 struct 来拥有一个固定的内存地址.到目前为止,我发现:
Pin
个指针;pin_mut
个宏以固定在堆栈上;PhantomPinned
,我不清楚.如果我理解正确,PhantomPinned
将是最容易使用的:将其作为成员将使我的 struct 自动拥有固定的内存地址.对吗?
你需要的是Pin
美元.它是一个指针,可以防止你的物体被移动.
pin_mut!()
只是一个宏,它可以帮助您创建一个Pin
实例,而不需要堆分配或unsafe
代码.
PhantomPinned
还有另一个目标,尽管相关.默认情况下,您的类型将实现Unpin
trait(除非它包含一个不实现Unpin
的类型,而大多数类型都实现).这是有问题的,因为对于实现Unpin
的类型,Pin
没有效果:它不会阻止您移动它们.这是因为大多数类型不需要固定的内存地址.例如,考虑一下i32
:即使创建Pin<&mut i32>
,也可以移动它,因为i32
实现了Unpin
,因为即使移动它,也不会发生任何不好的事情,也不会验证任何数据.
所以要想让Pin
有效,你需要取消impl Unpin
.这可以通过包含一个本身没有实现Unpin
的字段来实现,或者包含一个负impl(参见What is an auto trait in Rust?):
impl !Unpin for MyType {}
不幸的是,负面影响是不稳定的.相反,标准库提供了PhantomPinned
类型,这是无成本的(一个ZST),但没有实现Unpin
(它有一个负impl,因为标准库允许使用不稳定的特性,所以它可以做到这一点).现在当你的类型包括它时,它也变成了!Unpin
.
总之,你需要在你的 struct 中包含PhantomPinned
,这样它就不会是Unpin
,你需要把它包装成Pin
,这样它就不可移动了.