Rust中关于Pin的解读
创作时间:
作者:
@小白创作中心
Rust中关于Pin的解读
引用
1
来源
1.
https://juejin.cn/post/7401042923490623488
在Rust语言中,当遇到自引用结构需要进行移动操作时,可能会导致指针指向异常的问题。为了解决这一问题,Rust提供了Pin类型。本文将通过具体代码示例,深入探讨Pin的工作原理及其应用场景。
在Rust中,当存在自引用的结构时,在进行移动操作时,可能会导致指针指向原始地址不存在或者一直执行原地址,从而使得移动后指针指向的内容出现问题。为了解决这一问题,Rust提供了Pin类型来实现解决方案。Pin可以看作是对引用的再次封装。
下面是未使用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后,正常引用的示例:
use std::pin::Pin;
fn main() {
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();
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后,每次执行as_mut
都会重新生成一个Pin,而Pin只实现了Deref
,没有实现Ref
,因此只会返回一个原始引用,即使操作原始引用也不会影响当前的值。如果不使用Pin,就会导致使用的是同一个引用,其他地方修改了引用当前就会受到影响。
再来看看Pin的实现细节:
从上图可以看出,Pin的实现主要涉及Deref
、get_ref
和as_ref
等方法。这些方法确保了Pin在移动时能够保持其内部数据的稳定性,避免了指针指向异常的问题。
本文介绍了Rust中Pin类型的基本使用场景和解决方案,通过对比使用Pin前后的代码示例,帮助读者理解Pin在处理自引用结构时的作用。希望本文能够帮助Rust开发者更好地理解和使用Pin类型。
本文原文来自掘金
热门推荐
创始人“弃药从酒”?国台酒业上市前景未明朗
香港保险公司投资底层一览:八大公司财报与投资策略全比较
电脑主机如何无缝连接两个显示器?详细指南带你探索高清视觉盛宴
中塞直航助推塞尔维亚旅游热
从钉钉打卡6次到智能考勤管理:HR如何用数字化工具解放双手
站在2025,看人工智能与机器人的相互促进
卧室装修材料该怎么选择?
LPL第一赛段淘汰赛败者组:TES3-1力克IG晋级,下轮将对阵NIP
中年妇女减肥操(中老年健身三十六节全套)
革新与突破:关于手机屏的深度探索与前瞻
山水“养”出来的焦作有多好“吃”?!
办理退休需要提前多长时间办理
承载着历史和文化的旧书,如何在新时代找到新知己
每年花费数万亿美元,美国医疗仍排名最末
小宝宝发烧的症状有哪些
石榴是“中华神果”,能美容、抗癌?紧急提醒:这类人真不建议多吃!
地上2米地下5米,1.5万根“铁柱”插在青藏铁路两旁,揭秘其独特功能
冥想究竟是怎么让你变聪明的?
儿童营养不良怎么调理
史上最具标志性的10款摩托车
死亡后注销户口需要什么手续
洗衣机排水不畅的原因及解决方法
房贷还款最后还款期限及注意事项详解
平行宇宙真实存在?科学家:我们的宇宙或仅是无数“泡沫”之一!
简述边际效用递减规律并举例
这味中药是名副其实的美白“神器”,可内服可外用
汽车美容师的岗位技能与职责
广西全景深度三日游:必去景点、行程规划与旅行贴士
网络钓鱼的奥秘:探索其成功背后的心理机制及有效防御策略
烤冷面:东北特色小吃的魅力