Rust - Pin | Unpin | PhantomPinned

一、Pin<T> 是一种可以固定住内存地址的容器。

主要是解决自引用结构体问题,比如一个struct有一个T字段和一个&T字段,彼此有借用关系,当struct被移动后,&T就会成为悬垂指针。使用Pin套娃一层后,不管Pin<T>怎么移动,都不会影响&T。

  • Pin::new():创建一个Pin<T>的套娃
  • Box::pin():创建一个Pin<Box<T>>的套娃

二、Unpin 是Pin的反操作,基本上所有的类型都实现了Unpin,表示是可以随意移动的。

如果想让Unpin变为Pinned,则可以使用marker:PhantomPinned

三、任何T,只要实现了Unpin,那么Pin<Box<T>>Box<T>是没有区别的,Pin<&mut T>也一样。

示例:

use std::ops::Deref;
use std::ptr::NonNull;
use std::marker::PhantomPinned;
use std::pin::Pin;

struct Unmovable {
    data: String,
    slice: NonNull<String>,
    _pin: PhantomPinned,
}

impl Unpin for Unmovable {}

impl Unmovable {
    fn new(data: String) -> Pin<Box<Self>> {
        let res = Unmovable {
            data,
            slice: NonNull::dangling(),
            _pin: PhantomPinned,
        };
        let mut boxed = Box::pin(res);

        let slice = NonNull::from(&boxed.data);

        unsafe {
            let mut_ref: Pin<&mut Self> = Pin::as_mut(&mut boxed);
            Pin::get_unchecked_mut(mut_ref).slice = slice;
        }
        boxed
    }
}

fn main() {
    let unmoved = Unmovable::new("hello".to_string());

    let mut still_unmoved = unmoved;

    let mut new_unmoved = Unmovable::new("world".to_string());

    std::mem::swap(&mut *still_unmoved, &mut *new_unmoved);
}

PS:new方法创建了一个Pinned的结构体,如果它没有实现Unpin,那么最后一步swap是操作不了的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章