一、Pin由来
在Rust中,自引用结构会导致,此变量被move后,其内部自引用的指针指向不改变,从而存在安全隐患 。
注意:Pin是一个struct。UnPin和!UnPin是trait。这个要分清。
二、方案
对原始的自引用结构,如何增加安全性,方案有以下两步:
1、里面加Phantompinned,
2、外面套上Pin,
这样新的结构被move后,可以保证里面的自引用的指针指向的内容正确。
基于以上分析,我们来进行相关验证:
1、验证普通的结构体move前后行为:move的行为会产生什么影响?
2、带自引用结构move前后的行为:是否存在安全隐患?
3、带PhantomPinned自引用结构move前后的行为:是否解决了原先产生的问题?
在行为方面,具体的考察在于指针地址,指针指向内容的变化,是否能揭示相关问题。
三、相关代码
因为不涉及外部库,cargo.toml文件不需要另列。main.rs代码如下:
use std::pin::Pin;
use std::marker::PhantomPinned;
// unpin结构,没有自引用
#[derive(Debug,Default)]
struct Free{
content: String,
}
// unpin结构 =>move后,ptr对应的指针还会指向原来的地址,但不能正确指向content内容
#[derive(Debug)]
struct SelfRef {
content: String,
_ptr: *const String,//对应content 或者是&String
}
impl SelfRef{
fn default() ->Self{
SelfRef{
content: String::from("hello world!"),
_ptr: std::ptr::null(),
}
}
fn set_ref_value(&mut self){
self._ptr = & self.content as *const String;
}
}
// !unpin结构,通过引入phantompinned,再pin后,SelfRefPinned被move后,_ptr对应指针可以正确指向content
#[derive(Debug)]
struct SelfRefPinned {
content: String,
_ptr: *const String,//对应content
_marker: PhantomPinned,
}
impl SelfRefPinned{
fn default() ->Self{
SelfRefPinned{
content: String::from("hello world!"),
_ptr: std::ptr::null(),
_marker: PhantomPinned,
}
}
// stack
fn set_ref_value_by_ref_mut(pinned_obj: Pin<&mut Self>) {
let content_ptr = &pinned_obj.content as *const String;
let mut_self_ref: &mut SelfRefPinned = unsafe {
pinned_obj.get_unchecked_mut() };
mut_self_ref._ptr = content_ptr;
}
// heap
fn set_ref_value_by_box_pin(mut pinned_obj: Pin<Box<Self>>) -