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是操作不了的。

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