如何使用具有自引用结构的 Pin 结构?

How to use the Pin struct with self-referential structures?

我正在尝试使用新的 Pin feature. After reading this blog post,我已经开始编写一些代码:

#![feature(pin, arbitrary_self_types)]
use std::mem::Pin;

pub struct Foo {
    var: i32,
}

pub struct FooRef<'i> {
    ref_var: &'i i32,
    other: i32,
}

pub struct SimpleRef<'data> {
    foo: Box<Foo>,
    bar: Option<FooRef<'data>>,
}

impl<'data> SimpleRef<'data> {
    fn new() -> SimpleRef<'data> {
        SimpleRef {
            foo: Box::new({ Foo { var: 42 } }),
            bar: None,
        }
    }

    fn init(mut self: Pin<SimpleRef<'data>>) {
        let this: &mut SimpleRef = unsafe { Pin::get_mut(&mut self) };
        let a = FooRef {
            ref_var: &this.foo.var,
            other: 12,
        };
        this.bar = Some(a);
    }
}

fn main() {}

但是我得到这个错误:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
  --> src/main.rs:27:45
   |
27 |         let this: &mut SimpleRef = unsafe { Pin::get_mut(&mut self) };
   |                                             ^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 26:5...
  --> src/main.rs:26:5
   |
26 | /     fn init(mut self: Pin<SimpleRef<'data>>) {
27 | |         let this: &mut SimpleRef = unsafe { Pin::get_mut(&mut self) };
28 | |         let a = FooRef {
29 | |             ref_var: &this.foo.var,
...  |
32 | |         this.bar = Some(a);
33 | |     }
   | |_____^
note: ...but the lifetime must also be valid for the lifetime 'data as defined on the impl at 18:1...
  --> src/main.rs:18:1
   |
18 | impl<'data> SimpleRef<'data> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   = note: ...so that the expression is assignable:
           expected &mut std::mem::Pin<'_, SimpleRef<'_>>
              found &mut std::mem::Pin<'_, SimpleRef<'data>>

我的代码和博客中代码的区别 post 是我使用的是带有生命周期参数的变量,而不是原始指针。
是否可以使用带有生命周期参数的变量 Pin?

Is it possible to use variables with lifetime parameters with Pin?

可能。

The difference between my code and the code in the blog post is that I'm using a variable with a lifetime parameter, instead of a raw pointer.

这改变了一切:Rust 语言不保证指针的有效性,但严格保证引用的有效性。

让我们检查一下引用的生命周期问题,看看为什么这篇文章专门使用原始指针(和 unsafe 代码)来解决这个问题。


Pin::get_mut的签名是:

pub unsafe fn get_mut<'b>(this: &'b mut Pin<'a, T>) -> &'b mut T

也就是说,只要对Pin的引用有效,引用才有效。

因为 Pin 是通过值作为参数传递的,所以它在函数范围的末尾被删除。然而,您试图在该点之后保留对它的引用。这是不安全

使用裸指针是可以的(未选中),因为任何试图使用裸指针的人都需要使用 unsafe 块,负责确保指针确实有效。