为什么我们使用 `Box::pin` 来取消固定,使用 `Pin::new` 来取消固定?

cal*_*vin 3 rust

在学习 Rust 中 Pin 的实现时,我感到很困惑。

我知道当一个类型不能安全移动时,它可以 impl !UnpinPin就是防止别人得到&mut T这些类型,让他们不能得到std::mem::swap

如果 Pin 是为!Unpin类型设计的,为什么我们不能直接调用Pin::new这些类型呢?

它给出如下错误。我知道我应该使用 Pin::new_unchecked,但为什么呢?

struct TestNUnpin {
    b: String,
}
impl !Unpin for TestNUnpin {}

// error: the trait `Unpin` is not implemented for `TestNUnpin`
std::pin::Pin::new(&TestNUnpin{b: "b".to_owned()});
Run Code Online (Sandbox Code Playgroud)

我的推理是:

  1. 固定是为了帮助!取消固定类型
  2. 我们可以将 !Unpin 类型传递给 Pin::new 以使它们不可移动。
  3. 对于 Unpin 类型,它们不能被 pinned,所以我们不能通过 Pin::new 创建

Apl*_*123 8

我认为您要查找的内容可以在 的安全部分找到Pin::new_unchecked。本质上,Pin应该保证固定值永远不会再次移动(除非它实现Unpin),即使在被Pin删除之后也是如此。这种失败的一个例子是Pin<&mut T>。您可以删除Pin,并且该值不再被借用,因此您可以自由地再次移动它,从而破坏Pin的核心保证。这是一个例子:

use std::marker::PhantomPinned;
use std::pin::Pin;

fn main() {
    let x = PhantomPinned;
    
    {
        let _pin = Pin::new(&x); // error[E0277]: `PhantomPinned` cannot be unpinned
    }

    let y = Box::new(x); // the PhantomPinned is moved here!
}
Run Code Online (Sandbox Code Playgroud)

如果不向借用检查器添加大量额外的复杂性,则此检查根本无法在编译时完成,因此它被标记为unsafe,本质上是说确保其工作是开发人员的工作。之所以Box::pin存在并且是安全的,是因为 的开发者Box可以保证它的安全:Box是一个拥有的、唯一的指针,所以一旦它Pin被删除,它的值也被删除,并且不再有任何方法可以移动该值。