Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
863 views
in Technique[技术] by (71.8m points)

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

I'm trying to use the new Pin feature. After reading this blog post, I've started to write some code:

#![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() {}

But I get this error:

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>>

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.
Is it possible to use variables with lifetime parameters with Pin?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

Probably.

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.

This changes everything: the Rust language makes no guarantee on the validity of pointers, but makes strict guarantees on the validity of references.

Let's examine the lifetime issue of references and see why the article specifically used raw pointers (and unsafe code) to overcome the issue.


The signature of Pin::get_mut is:

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

That is, the reference is only valid as long as the reference to Pin is valid.

Since Pin is passed by value as argument, it is dropped at the end of the function scope. Yet, you attempt to retain a reference to it beyond that point. This is unsafe.

Using raw pointers is fine (unchecked), because whoever attempts to use the raw pointer will need to use an unsafe block, taking responsibility for ensuring that the pointer is indeed valid.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...