Rust: 关于Pin以及move前后分析

一、Pin由来
在Rust中,自引用结构会导致,此变量被move后,其内部自引用的指针指向不改变,从而存在安全隐患 。

注意:Pin是一个struct。UnPin和!UnPin是trait。这个要分清。

二、方案

对自引用结构,如何增加安全性,方案以下两步:
1、里面加phantompinned,
2、外面套上Pin,
这样新的结构被move后,可以保证里面的自引用的指针指向的内容正确。

基于以上分析,我们来进行相关验证

1、验证普通的结构体move前后行为
2、带自引用结构move前后的行为
3、带PhantomPinned自引用结构move前后的行为
在行为方面,主要考察,指针地址,指针指向内容的变化,是否如上所述。

三、相关代码

use std::pin::{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后,对应指针可以正确指向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,}}fn set_ref_value(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;}
}
fn main() {let _free = Free::default();let mut _self_ref = SelfRef::default();_self_ref.set_ref_value();let mut self_ref_pin = SelfRefPinned::default();let mut _self_ref_pinned = unsafe { Pin::new_unchecked(&mut self_ref_pin) };SelfRefPinned::set_ref_value(_self_ref_pinned.as_mut());// before moveprintln!("-----------before move-------------");println!("_free content:{:?}  content 内存指针: {:p}",_free.content,&_free.content);// after moveprintln!("-----------after move-------------");let free_ = _free; //move操作println!("free_ content:{:?}  content 内存指针: {:p}",free_.content,&free_.content);println!("-----------before move-------------");println!("_self_ref 内存地址:{:p} content内存地址:{:p}",&_self_ref,&_self_ref.content);println!("_self_ref._ptr对应value :{:?}  自引用指针的内存地址: {:?}",unsafe{&*_self_ref._ptr},&_self_ref._ptr);// after moveprintln!("-----------after move-------------");let self_ref_ = _self_ref; //move操作println!("self_ref_ 内存地址:{:p} content内存地址:{:p}",&self_ref_,&self_ref_.content);println!("self_ref_._ptr对应value :{:?}  自引用指针的内存地址: {:?}",unsafe{&*self_ref_._ptr},&self_ref_._ptr);println!("-----------before move-------------");println!("_self_ref_pinned 内存地址:{:p} content内存地址:{:p}",&_self_ref_pinned,&_self_ref_pinned.content);println!("_self_ref_pinned._ptr对应value :{:?}  自引用指针的内存地址: {:?}",unsafe{&*_self_ref_pinned._ptr},&_self_ref_pinned._ptr);// after moveprintln!("-----------after move-------------");let self_ref_pinned_ = _self_ref_pinned; //move 操作println!("self_ref_pinned_ 内存地址:{:p} content内存地址:{:p}",&self_ref_pinned_,&self_ref_pinned_.content);println!("self_ref_pinned_._ptr对应value :{:?}  自引用指针的内存地址: {:?}",unsafe{&*self_ref_pinned_._ptr},&self_ref_pinned_._ptr);}

四、输出

-----------before move-------------
_free content:""  content 内存指针: 0x7ffc25c25850
-----------after move-------------
free_ content:""  content 内存指针: 0x7ffc25c25830
-----------before move-------------
_self_ref 内存地址:0x7ffc25c257f0 content内存地址:0x7ffc25c257f0
_self_ref._ptr对应value :"hello world!"  自引用指针的内存地址: 0x7ffc25c257f0
-----------after move-------------
self_ref_ 内存地址:0x7ffc25c257c0 content内存地址:0x7ffc25c257c0
self_ref_._ptr对应value :"hello world!"  自引用指针的内存地址: 0x7ffc25c257f0
-----------before move-------------
_self_ref_pinned 内存地址:0x7ffc25c257b8 content内存地址:0x7ffc25c25810
_self_ref_pinned._ptr对应value :"hello world!"  自引用指针的内存地址: 0x7ffc25c25810
-----------after move-------------
self_ref_pinned_ 内存地址:0x7ffc25c257e8 content内存地址:0x7ffc25c25810
self_ref_pinned_._ptr对应value :"hello world!"  自引用指针的内存地址: 0x7ffc25c25810

五、总结

1、从上面Free类型来看,move后,struct主体的指针有变动。
2、自引用结构变动后,可以看见对应的struct指针地址发生变化后,自引用对应指针并没有变动,并没指向所需的content的内容。
3、Pin之后,move其实没有任何影响。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/42967.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【VUE基础】VUE3第四节—核心语法之computed、watch、watcheffect

computed 接受一个 getter 函数&#xff0c;返回一个只读的响应式 ref 对象。该 ref 通过 .value 暴露 getter 函数的返回值。它也可以接受一个带有 get 和 set 函数的对象来创建一个可写的 ref 对象。 创建一个只读的计算属性 ref&#xff1a; <template><div cl…

C语言 输出10行杨辉三角形

输出以下的杨辉三角形(要求输出10行)。 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 … #include <stdio.h>int main() {int triangle[10][10] {0};for (int i 0; i < 10; i) {triangle[i][0] 1;triangle[i][i] 1;for (int j 1; j < i…

<PLC><汇川><串口485>汇川Eazy521系列PLC与特域水冷机进行485通讯的设置

前言 本系列是关于PLC相关的博文,包括PLC编程、PLC与上位机通讯、PLC与下位驱动、仪器仪表等通讯、PLC指令解析等相关内容。 PLC品牌包括但不限于西门子、三菱等国外品牌,汇川、信捷等国内品牌。 除了PLC为主要内容外,PLC相关元器件如触摸屏(HMI)、交换机等工控产品,如…

【前端界面分享】

实现效果&#xff1a;html源码来自b站up主&#xff1a;【CSSJS】甲方&#xff1a;啊&#xff1f;没叫你做那么超前啊_哔哩哔哩_bilibili 本人仅实现了将html格式改为vue3 html版&#xff1a; 对于前端连入门可能都没摸到&#xff0c;学了半天也就改成vue3了&#xff0c;对于输…

杂项——循迹模块调节方法

1-4 路灰度传感器的调节方法&#xff1a; 调节时探头应对着颜色较浅的上方&#xff08;如果是黑白线赛道则应该将探头 对着白色上方调&#xff09;&#xff0c;轻轻的将全部可调电阻顺时针拧到底&#xff0c;再逆时针 慢慢回旋&#xff0c;直到对应探头的信号指示灯亮起后&…

C# 开发Winform DataGridView的增删改查实战

在C# WinForms应用程序中&#xff0c;DataGridView控件是一个非常强大的工具&#xff0c;用于显示和编辑表格数据。下面我将详细介绍如何在WinForm应用程序中使用DataGridView实现基本的数据库操作&#xff1a;增加、删除、修改和查询&#xff08;CRUD&#xff09;。 第一步&a…

【ARM系列】1 of N SPI

1 of N模式 SPI 概述配置流程 概述 GIC-600AE支持1 of N模式SPI。在此模式下可以将SPI target到多个core&#xff0c;并且GIC-600AE可以选择哪些内核接收SPI。 GIC-600AE只向处于powered up 并且使能中断组的core发送SPI。 GIC-600AE会优先考虑那些被认为是active的核&#xf…

小程序 全局数据共享 getApp()

在小程序中&#xff0c;可以通过 getApp() 方法获取到小程序全局唯一的App实例 因此在App() 方法中添加全局共享的数据、方法&#xff0c;从而实现页面、组件的数据传值 在 app.js 文件中定义 App({// 全局共享的数据globalData:{token:},// 全局共享的方法setToken(token){//…

如何创建一个基本的Mojolicious Web应用:探索Perl的现代Web框架

如何创建一个基本的Mojolicious Web应用&#xff1a;探索Perl的现代Web框架 Mojolicious是一个用Perl编写的简单、优雅的Web开发框架&#xff0c;它提供了一套丰富的工具和方法&#xff0c;让开发者能够快速构建高性能的Web应用。本文将详细介绍如何创建一个基本的Mojolicious…

面向对象——继承、封装、多态

什么是面向对象&#xff1f; 面向对象&#xff08;Object-Oriented Programming&#xff0c;简称OOP&#xff09;是一种编程范式&#xff0c;它使用“对象”来设计应用程序和计算机程序。OOP的核心概念包括类&#xff08;Class&#xff09;、对象&#xff08;Object&#xff09…

SQL注入基础入门

文章目录 前言SQL注入基本操作SQL注入类型分类数字型字符型搜索型xx型Json型数据类型提交的方式 SQL注入的位置分类报错注入报错注入实战案例 SQL注入语句分类insert注入update注入delete注入 编码Tips&#xff1a;Mysql版本区别information_schema数据库详解 其他注入手段宽字…

面试官:Java线程可以无限创建吗?

1. 面试连环call Java线程可以无限创建吗? Java线程和操作系统线程有什么关联? 操作系统为什么要区分内核态和用户态? ⏩要想解答这些问题&#xff0c;我们要先从操作系统线程开始说起&#xff0c;让我们开始吧&#x1f389;&#x1f389;&#x1f389; 2. 操作系统线程…

为什么要学习Go

本文旨在探讨为什么Go语言值得学习,以及它如何能够提升您的编程技能和职业发展。我们将深入分析Go语言的核心优势,包括其简洁的语法、强大的并发支持、卓越的性能表现,以及在云计算、微服务和系统编程等领域的广泛应用 GO logo的核心理念&#xff0c;即简单胜于复杂。使用现代…

Redis-Redis可视化工具Redis Insight下载及安装

下载 1、博主已经上传资源&#xff0c;点此下载 2、点此进入官方下载 2.1 点击Installing Redis Insight 2.2 点击Install on desktop 2.3 选择Install on desktop&#xff0c;点击Redis Insight is available for download for free from this web site从网站下载 2.4 下载…

大模型简介

文章目录 大模型简介什么是大模型GPT大语言模型发展大语言模型对话产品大模型怎么用 大模型简介 什么是大模型 大模型&#xff0c;全称「大语言模型」&#xff0c;英文「Large Language Model」&#xff0c;缩写「LLM」。是具有大量参数和复杂结构的机器学习模型。大模型通常…

Python 可视化 web 神器:streamlit、Gradio、dash、nicegui;低代码 Python Web 框架:PyWebIO

官网&#xff1a;https://streamlit.io/ github&#xff1a;https://github.com/streamlit/streamlit API 参考&#xff1a;https://docs.streamlit.io/library/api-reference 最全 Streamlit 教程&#xff1a;https://juejin.cn/column/7265946243196436520 Streamlit-中文文档…

MYSQL 四、mysql进阶 7(性能分析工具的使用)

一、数据库服务器的优化步骤 数据库调优流程图: 整个流程划分成了 观察&#xff08;Show status&#xff09; 和 行动&#xff08;Action&#xff09; 两个部分。字母 S 的部分代表观察&#xff08;会使 用相应的分析工具&#xff09;&#xff0c;字母 A 代表的部分是行…

算法012:将x减到0的最小操作数

将x减到0的最小操作数. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/ 这个题使用到的是滑动窗口。 乍一看&#xff0c…

U盘管理软件有哪些?3款好用的软件亲测有效!

在数字化办公与数据交换日益频繁的今天&#xff0c;U盘作为便携的存储设备&#xff0c;其重要性不言而喻。 然而&#xff0c;U盘的使用也带来了数据泄露、病毒感染等安全隐患。为了有效管理U盘&#xff0c;确保数据安全与合规性&#xff0c;市场上涌现出了众多U盘管理软件。 小…

大话C语言:第29篇 指针

1 指针概念 指针&#xff1a;地址的变量化形式&#xff0c;其存储的是内存中某个存储单元的地址。它是地址的数值表示。 指针变量&#xff1a;一种特殊的变量&#xff0c;它专门用于存放变量的地址&#xff08;即指针&#xff09;。 注意&#xff0c;指针和指针变量的区别&am…