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类型。
本文原文来自掘金
热门推荐
枣强出租车服务台怎么提升服务质量?
开封市博物馆里“卷”的狠,个个都想当镇馆之宝
双眼皮两边不对称该如何解决?有哪些有效的方法可以改善?
针灸时出现滞针、断针、晕针怎么办?
协议只盖公章有法律效力吗
取环后出现腹痛能否服用布洛芬
猫咪呼吸道感染应对策略(以宠物为主)
厨房小白必看,料酒VS黄酒:究竟谁才是厨房之王
拿奖又发财!细看周冬雨的升咖之路和资产,贵人和运气都少不了
寒冷地区适合种什么农作物?哪些作物能在低温环境下生长?
杜仲育种新突破:‘华仲30号’杜仲国审良种选育成功
备战中高考,“脑黄金”DHA是智商税吗?
线上起诉立案怎么操作
黑曜石:神秘宝石的前世今生
做到这五点,你也能轻松控糖
如何腌制腊肉最正确方法(才知道腌腊肉不能直接抹盐教你正确做法)
乳胶漆颜色选择及影响因素
高斯混合模型 (Gaussian Mixture Model)
开曼公司注册一站式指南:流程、优势与后续维护指南(2025最新)
江苏省中医院专家推荐:六类食物助你有效控制血压
从梦中挽回前任的心结(如何以梦为线索重拾感情?)
嘴里发苦,暗示身体可能有这8个问题,别大意了
如果你忘记了 Mac 登录密码
耳机里的声音为什么会有方向感?
励志系动物电影有哪些
帕金森病患者为何有流口水症状
法甲斯特拉斯堡vs欧塞尔今日预测 斯特拉斯堡依靠主场抢分
百合竹的叶子发黄了怎么办
焖子的营养价值
清关代理费都包含哪些费用?