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

如果我理解正确,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,这样它就不可移动了.

Rust相关问答推荐

如何处理对打包字段的引用是未对齐错误?

通过不同的字段进行散列和排序的 struct (需要不同的EQ实现)

防止cargo test 中的竞争条件

如果包名称与bin名称相同,并且main.ars位于工作区的同一 crate 中,则无法添加对lib.ars的依赖

如果死 struct 实现了/派生了一些特征,为什么Rust会停止检测它们?

为什么`str`类型可以是任意大小(未知大小),而`string`类型的大小应该是已知的?

为什么我需要 to_string 函数的参考?

找不到 .has_func 或 .get_func 的 def

.在 Rust 模块标识符中

如何将一个矩阵的列分配给另一个矩阵,纳尔代数?

使用 pyo3 将 Rust 转换为 Python 自定义类型

`UnsafeCell` 在没有锁定的情况下跨线程共享 - 这可能会导致 UB,对吗?

可选包装枚举的反序列化

当推送到 HashMap 中的 Vector 时,类型 `()` 无法取消引用

为什么这个闭包没有实现Fn?

为什么Rust编译器会忽略模板参数应具有静态生命周期?

n 个范围的笛卡尔积

Rust 中函数的类型同义词

在单独的线程上运行 actix web 服务器

为什么 `ref` 会导致此示例*取消引用*一个字段?