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