Rust中关于Pin的解读

207 阅读2分钟

在rust中,对应存在自引用的结构,在进行move的时候,会存在问题,导致指针指向原始的地址不存在或者一直执行原地址,导致move过后指针指向的内容有问题。这种情况下rust提供了Pin来实现解决方案。Pin相当于是对应引用的再一次封装。

下图为没有使用Pin时,move后导致指向异常问题:

图片.png

下图为使用了Pin后,正常的引用:

图片.png


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

图片.png 再看看get_ref

图片.png 以及as_ref

图片.png