Pin
是否只是一个语义保证,仅由unsafe
代码依赖,在调用堆栈的末尾?是否有任何完全安全的Rust结构或API在没有固定值的情况下无法工作/编译?(除了调用需要Pin<T>
的函数)
我想我理解Pin是如何“工作”的(它并没有真正做任何事情),以及它代表了什么。我只是想知道,除了在调用堆栈的unsafe
代码中的某个地方最终拥有一个稳定的原始指针之外,这种新类型提供的保证是否有用。
1“safe”,即“not unsafe
“,我并不是在暗示标准库中的unsafe
代码实际上是不安全/不可靠的
2条答案
按热度按时间w8biq8rn1#
下面的代码是完全安全的(如果你不看
Box
和String
的话),它包含了一个自引用:字符串
async
块包含借用其他变量的变量,产生包含自引用的Future
s,并且它们不是使用unsafe
代码定义的。当然,这可能是一个不令人满意的例子,因为虽然用法不是
unsafe
,但显式使用已经存在的Pin
也是不安全的代码-对固定未来内容的访问隐藏在编译器对代码的转换中。原则上,你可以定义一个类型,它使用自己的 address,比如在某个表中使用它作为键。在这种情况下,
Pin
保证将确保地址永远不会改变,直到值被Drop
ped,这正是你想要的,以便在删除值之前有一个稳定的键。这本质上是自引用的一种奇怪情况,因为它使用指向自身的指针,但不是通过实际 * 解引用 * 这些指针,所以它可以在完全安全的代码中完成。
但是,这并不是使用
Pin
的实际原因。您通常可以通过使用AtomicU64
全局计数器方便地获得唯一ID(不需要释放,因为在程序停止运行之前不可能溢出),这可以完全在类型内部完成,而不需要所有者遵循Pin
规则。为了从
Pin
使用地址作为ID的规则中获益,您需要做一些更具体的事情,例如希望struct
的结构固定成员能够获得总是以升序匹配字段顺序的ID。在这种情况下,
Pin
提供了与组合future相同的好处:每个元素都得到了稳定地址的保证,而不必创建自己的堆分配。(没有组合,你还不如通过堆分配你的内容来创建一个稳定地址--这就是ouroboros
在没有Pin
的情况下启用自引用的方法。)gzszwxb42#
the standard library和this Cloudflare blog post都解释了
Pin
是为自引用结构体而存在的(尽管它们没有排除它用于其他目的的实用性,但它们没有提到任何用途)。从技术上讲,自引用结构体不能用完全安全的代码编写,因此需要使用
unsafe
。然而,Pin
的存在是因为没有它,就没有办法在安全代码中安全地使用自引用结构体,因为编译器可以并且确实在某些情况下移动值。因此,目标是将潜在的不安全行为限制在unsafe
块上,并且不让编译器通过移动值来代表自己引入它,这将被认为是编译器中的bug。