幻像成员会使我的结构具有固定的内存地址吗?
我正在编写与 C API 通信的 Rust 代码,并且我需要某个结构来拥有固定的内存地址。到目前为止,我发现:
Pin
用于指针;- 要固定的
pin_mut
宏堆栈; PhantomPinned
,这不是我很清楚。
如果我理解正确的话,PhantomPinned
将是最容易使用的:只需将其作为成员即可使我的结构自动具有固定的内存地址。这是正确的吗?
I'm writing Rust code which communicates with a C API, and I need a certain struct to have a fixed memory address. So far, I found:
Pin
for pointers;pin_mut
macro to pin on the stack;PhantomPinned
, which is not clear to me.
If I understood correctly, PhantomPinned
would be the easiest to use: just having it as a member would make my struct automatically have a fixed memory address. Is this correct?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您需要的是
Pin
。它是一个防止对象移动的指针。pin_mut!()
只是一个宏,可帮助您创建一个Pin
实例,而无需堆分配或不安全
代码。PhantomPinned
还有另一个相关的目标。默认情况下,您的类型将实现Unpin
特征(除非它包含不实现
Unpin
的类型,但大多数类型都实现)。这是有问题的,因为对于实现Unpin
的类型,Pin
没有效果:它不会阻止您移动它们。这是因为大多数类型不需要固定的内存地址。想想i32
,例如:即使您创建了Pin<&mut i32>
,您也可以移动它,因为i32
实现了取消固定
,因为即使您移动它也不会发生任何不良情况,并且不会验证任何数据。因此,为了使
Pin
有效,您需要取消实现Unpin
。这是通过包含一个不将Unpin
本身实现为字段的字段,或者具有一个负 impl 来完成的(请参阅 什么是 Rust 中的自动特征?):不幸的是,负 impls 不稳定。相反,标准库提供了
PhantomPinned
类型,这是无成本的(ZST),但没有实现Unpin
(它有一个负面的隐含,因为标准库是允许使用不稳定的功能它可以做到这一点)。现在,当您的类型包含它时,它也会变成!Unpin
。总而言之,您需要在结构中包含
PhantomPinned
,这样它就不会被Unpin
,并且您需要将其包装在Pin
中,这样它就可以将无法移动。What you need is
Pin
. It's a pointer that keeps your object from being moved.pin_mut!()
is just a macro that helps you create aPin
instance without heap allocation orunsafe
code.PhantomPinned
has another, though related, goal. By default, your type will implement theUnpin
trait (unless it contains a type that don't implementUnpin
, however most types do). This is problematic, because for types that implementsUnpin
,Pin
has no effect: it does not prevent you from moving them. This is because most types do not need a fixed memory address. Think abouti32
, for example: even if you createPin<&mut i32>
, you can move it, becausei32
implementsUnpin
, because even if you'll move it nothing bad will happen, and no data will be validated.So for
Pin
to be effective you need to un-implUnpin
. This is done by either including a field that doesn't implementsUnpin
itself as a field, or having a negative impl (see What is an auto trait in Rust?):Unfortunately, negative impls are unstable. Instead, the standard library provides the
PhantomPinned
type, which is costless (a ZST), but doesn't implementUnpin
(it has a negative impl, since the standard library is allowed to use unstable features it can do that). And now when your type includes it it becomes!Unpin
too.To sum up, you need to include
PhantomPinned
in your struct so it will not beUnpin
, and you need to wrap it inPin
so it will be unmovable.Rust中唯一的不容易变化的值是
pin&lt; t&gt;
中的值,并且仅当t
不实现unpin
时。t
可能是参考或某些智能指针类型,例如box
arc ,但pin> pin
以指定该指定。该值可能不会移动。undin
是针对不在乎他们是否被固定的类型实现的特征。这是一个标记性状自动针对所有类型的成员实现unpin
的类型。phantompinned
是一种简单的零大小类型实施UNVIN
。请注意,
unvin
仅与pin> pin
包装值 -PIN> PIN
之外的值仍然可以移动。需要不移动该值的操作应采用pin&lt;&amp; mut t&gt;
而不是&amp; mut t
。pin_mut
是将堆栈值转换为固定指针的宏。对于已知安全案例来说,这只是一个方便,并没有真正涉及PIN
的工作方式。因此,对于您的情况,听起来您的结构应该具有
phantompined
成员,并且其所有操作都应采用PIN包装参考。The only unmoveable value in Rust is the value in
Pin<T>
and only ifT
does not implementUnpin
.T
may be a reference or some smart pointer type likeBox
orArc
, butPin
is needed to specify that the value may not move.Unpin
is a trait implemented for types that don't care if they are moved, even if they are pinned. It's a marker trait automatically implemented for all types whose members all implementUnpin
.PhantomPinned
is a simple, zero sized type that does not implementUnpin
, so it may be added to a struct or enum to make it not automatically implementUnpin
.Note that
Unpin
is only relevant toPin
wrapped values - values outside ofPin
can still be moved. Operations requiring the value not be moved should take aPin<&mut T>
instead of&mut T
.pin_mut
is a macro for converting a stack value to a pinned pointer. It's just a convenience for a known-safe case and doesn't really play into howPin
works.So for your case, it sounds like your structure should have a
PhantomPinned
member, and all of its operations should take a pin-wrapped reference.