Pin的产生
rust中有些数据结构可能会携带指向自身的指针,比如:
struct A {
data: 1,
ptr: 0x01, //data字段内存地址
}
特别是rust异步函数编译生成的代码就可能会有这种结构(其实基本也就跟异步编程有关)。
这种结构的数据如果被移动了(通过获取其可变引用,再mem::replace等等),那其字段data也被移动了,但字段ptr还指向原来的值,这个ptr就坏了,变成了悬垂指针。
所以需要一个标识来保证某些数据不会被移动,不然future的实现不能使用这些内存不安全数据, 这个标识就是类型Pin。
Pin的原理
pub const fn get_mut(self) -> &'a mut T
where T: Unpin
Pin<T>通过带Unpin约束的get_mut方法来限制用户获取类型T的可变引用,从而保证被Pin包裹的数据不会被移动。
因为要安全地获取被Pin的数据T的可变引用的前提是类型T是Unpin的,
而这个Unpin是一个rust自实现的标记trait,用来表示类型可以被安全的移动,比如i32,String等类型,这些类型本来就不会被安全的方法如mem::replace移动数据,只会被复制。
总结一下Pin<T>提供的保证就是,只有类型T可以被安全的移动时,才能通过安全方法获取其可变引用。
有了Pin就能保证future内的数据都是不会被移动的。
Pin的创建方法
关于Pin的创建方法可以简单的概括为,
- 把数据移到栈上,这样数据不会被移动,只会被复制。
- 用智能指针包装数据,这样移动数据的操作也只是复制这个指针而已。