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