在rust中,对应存在自引用的结构,在进行move的时候,会存在问题,导致指针指向原始的地址不存在或者一直执行原地址,导致move过后指针指向的内容有问题。这种情况下rust提供了Pin来实现解决方案。Pin相当于是对应引用的再一次封装。
下图为没有使用Pin时,move后导致指向异常问题:
下图为使用了Pin后,正常的引用:
use std::pin::Pin;
fn main() {
// pin就相当于额外包装了一层指针,移动的时候,直接整体移动,就不会出现问题
// pin每次执行as_mut 会重新生成一个pin
// pin只实现了Deref,没有实现Ref,此时只会返回一个原始引用,所以即使操作原始引用也不会影响当前的值
// 当不使用Pin的时候,就会导致使用的是同一个引用,其他地方修改了引用当前就会受到影响
let mut data1 = SelfReference::new("hello");
// let mut data1 = unsafe { Pin::new_unchecked(&mut data1) };
data1.init();
let mut data2 = SelfReference::new("world");
// let mut data2 = unsafe { Pin::new_unchecked(&mut data2) };
data2.init();
data1.print();
data2.print();
// 如果使用了Pin那么就相当于:重新定义了2个新的引用指向pin的数据,然后进行交换,此时新的引用和原来的引用是隔离的,所以不会相互影响
// 但是如果不使用Pin那么就相当于:直接交换了2个引用,所以会相互影响
std::mem::swap(&mut data1, &mut data2);
data1.print();
data2.print();
}
#[derive(Debug)]
struct SelfReference {
name: String,
// 在初始化后指向 name
name_ptr: *const String,
}
impl SelfReference {
pub fn new(name: impl Into<String>) -> Self {
let name = name.into();
SelfReference {
name,
name_ptr: std::ptr::null(),
}
}
pub fn init(&mut self) {
self.name_ptr = &self.name as *const String;
}
pub fn print(&self) {
println!("{:?} {} {}", self, self.name, unsafe { &*self.name_ptr })
}
}
可以看看Pin的实现的Deref
再看看get_ref
以及as_ref