当前位置: 首页 > news >正文

Rust 解决循环引用

导航

  • 循环引用
    • 一、现象
    • 二、解决

循环引用

循环引用出现的一个场景就是你指向我我指向你,导致程序崩溃

解决方式可以通过弱指针,而Rust中的弱指针就是Weak

Rc中,可以实现,对一个变量,持有多个不可变引用,并且都拥有该变量的所有权,这种情况下就可能会发生循环引用的现象

一、现象

从代码中来,到代码中去,先上个图
在这里插入图片描述

use crate::List::{Cons, Nil};
use std::cell::RefCell;
use std::rc::Rc;#[derive(Debug)]
enum List {Cons(i32, RefCell<Rc<List>>),Nil,
}impl List {fn tail(&self) -> Option<&RefCell<Rc<List>>> {match self {Cons(_, item) => Some(item),Nil => None,}}
}
fn main() {//Cons(5, RefCell::new(Rc::new(Nil)))已经有一个拥有者alet a = Rc::new(Cons(5, RefCell::new(Rc::new(Nil))));println!("a的初始化rc计数 = {}", Rc::strong_count(&a));println!("a指向的节点 = {:?}", a.tail());// 创建`b`到`a`的引用//b指向的结构体Cons(10, RefCell::new(Rc::clone(&a)),结构体字段也拥有了Cons(5, RefCell::new(Rc::new(Nil))//对于Cons(10, RefCell::new(Rc::clone(&a)结构体,只有一个拥有者blet b = Rc::new(Cons(10, RefCell::new(Rc::clone(&a))));//所以对于Cons(5, RefCell::new(Rc::new(Nil)))已经有了两个拥有者println!("在b创建后,a的rc计数 = {}", Rc::strong_count(&a));//这里是2println!("b的初始化rc计数 = {}", Rc::strong_count(&b));//这里是1println!("b指向的节点 = {:?}", b.tail());// 利用RefCell的可变性,创建了`a`到`b`的引用if let Some(link) = a.tail() {//因为 Cons(i32, RefCell<Rc<List>>)内部定义的是RefCell,可以修改指向,指向另一个Rc*link.borrow_mut() = Rc::clone(&b);//指向b}//对于Cons(10, RefCell::new(Rc::clone(&a)已经有b和a结构体中的Cons字段,两个所有者println!("在更改a后,b的rc计数 = {}", Rc::strong_count(&b));//对于Cons(5, RefCell::new(Rc::clone(&b)已经有a和b结构体中的Cons字段,两个所有者println!("在更改a后,a的rc计数 = {}", Rc::strong_count(&a));// 下面一行println!将导致循环引用//Rc指向的对象被drop的原则是,所有拥有者已经失去所有权,如果不主动drop,就无法解开引用// 下面一行println!将导致循环引用// 我们可怜的8MB大小的main线程栈空间将被它冲垮,最终造成栈溢出,Debug特征会一直打印每个结构体的字段,所以会递归// println!("a next item = {:?}", a.tail());
}

二、解决

Weak 非常类似于 Rc,但是与 Rc 持有所有权不同,Weak 不持有所有权,借用的值可以在生命周期结束后正常drop掉,就不会出现循环引用了.

WeakRc不同的地方是:

  1. 获取一个没有所有权的引用方式是,Rc::downgrade(&)
  2. 获取借用值是upgrade(),返回的是Option<Rc> ,值存在就返回引用,不存在就返回None
use std::rc::Rc;
use std::rc::Weak;
use std::cell::RefCell;// 主人
struct Owner {name: String,gadgets: RefCell<Vec<Weak<Gadget>>>,
}// 工具
struct Gadget {id: i32,owner: Rc<Owner>,
}fn main() {// 创建一个 Owner// 需要注意,该 Owner 也拥有多个 `gadgets`let gadget_owner : Rc<Owner> = Rc::new(Owner {name: "Gadget Man".to_string(),gadgets: RefCell::new(Vec::new()),});// 创建工具,同时与主人进行关联:创建两个 gadget,他们分别持有 gadget_owner 的一个引用。let gadget1 = Rc::new(Gadget{id: 1, owner: gadget_owner.clone()});let gadget2 = Rc::new(Gadget{id: 2, owner: gadget_owner.clone()});// 为主人更新它所拥有的工具// 因为之前使用了 `Rc`,现在必须要使用 `Weak`,否则就会循环引用gadget_owner.gadgets.borrow_mut().push(Rc::downgrade(&gadget1));gadget_owner.gadgets.borrow_mut().push(Rc::downgrade(&gadget2));// 遍历 gadget_owner 的 gadgets 字段for gadget_opt in gadget_owner.gadgets.borrow().iter() {// gadget_opt 是一个 Weak<Gadget> 。 因为 weak 指针不能保证他所引用的对象// 仍然存在。所以我们需要显式的调用 upgrade() 来通过其返回值(Option<_>)来判// 断其所指向的对象是否存在。// 当然,Option 为 None 的时候这个引用原对象就不存在了。let gadget = gadget_opt.upgrade().unwrap();println!("Gadget {} owned by {}", gadget.id, gadget.owner.name);}// 在 main 函数的最后,gadget_owner,gadget1 和 gadget2 都被销毁。// 具体是,因为这几个结构体之间没有了强引用(`Rc<T>`),所以,当他们销毁的时候。//!!!!!!// 首先 gadget2 和 gadget1 被销毁。// 然后因为 gadget_owner 的引用数量为 0,所以这个对象可以被销毁了。// 循环引用问题也就避免了
}

在这里插入图片描述

相关文章:

Rust 解决循环引用

导航 循环引用一、现象二、解决 循环引用 循环引用出现的一个场景就是你指向我&#xff0c;我指向你&#xff0c;导致程序崩溃 解决方式可以通过弱指针&#xff0c;而Rust中的弱指针就是Weak 在Rc中&#xff0c;可以实现&#xff0c;对一个变量&#xff0c;持有多个不可变引…...

ICC2:如何解决pin density过高引起的绕线问题

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 为了追求极致的利用率,综合往往会使用大量的AOI/OAI等多pin cell,然而后端实现过程中,工具为了解决绕线难题,又会通过降低local density的方法实现反向奔赴,即便如此,绕线后仍会残留不少问题,…...

Buuctf-Misc题目练习

打开后是一个gif动图&#xff0c;可以使用stegsolve工具进行逐帧看。 File Format:文件格式 Data Extract:数据提取 Steregram Solve:立体试图 可以左右控制偏移 Frame Browser:帧浏览器 Image Combiner:拼图&#xff0c;图片拼接 所以可以知道我们要选这个Frame Browser …...

费马小定理详解

费马小定理 定义&#xff1a; 设 p 为素数&#xff0c;a 为整数&#xff0c;则 a p ≡ a ( m o d p ) a^p \equiv a\ (\mod p) ap≡a (modp) &#xff0c;若 p ∤ a p \nmid a p∤a &#xff0c;则 a p − 1 ≡ 1 ( m o d p ) a^{p-1} \equiv 1\ (\mod p) ap−1≡1 (modp)…...

PXE批量安装

系统装机的三种引导方式 u盘光盘网络装机 光盘&#xff1a; 1.类似于usb模式 2.刻录模式 系统安装过程 加载boot loader Boot Loader 是在操作系统内核运行之前运行的一段小程序。通过这段小程序&#xff0c;我们可以初始化硬件设备、建立内存空间的映射图&#xff0c;从…...

stm32f103c8t6最小系统板

STM32F103C8T6最小系统板是为基于ARM Cortex-M3内核的STM32F103C8T6微控制器设计的电路板&#xff0c;它包含了单片机正常运行所需的最基本组件。以下是构成STM32F103C8T6最小系统板的基本部分&#xff1a; 单片机芯片&#xff1a;STM32F103C8T6本身&#xff0c;它是一款32位微…...

QCefView 在 Linux 下的编译(更新)

在前面的文章《QT 应用程序中集成浏览器》中已经介绍过 QCefView 的构建。这几天发现 QCefView 代码进行了更新,构建方式也发生了一点点变化,所以在此更新一下 QCefView 的编译方法。 QCefView 其实包含了两个项目,一个就是 QCefView 项目本身,另外一个就是 CefViewCore。…...

无卤素产品是什么?有什么作用?

无卤素产品&#xff0c;即在生产过程中完全不使用卤素元素——氟、氯、溴、碘等——的产品。 卤素元素&#xff0c;虽然在电子设备、材料等领域应用广泛&#xff0c;却也可能潜藏危害。其阻燃剂&#xff0c;一旦在产品生命周期结束后释放&#xff0c;将对土壤和水体造成污染&a…...

esp32-cam 1. 出厂固件编译与测试

0. 环境 - ubuntu18 - esp32-cam - usb转ttl ch340 硬件连接 esp32-camch340板子U0RTXDU0TRXDGNDGND5V5V 1. 安装依赖 sudo apt-get install vim sudo apt install git sudo apt-get install git wget flex bison gperf python python-pip python-setuptools python-serial p…...

题目:线性代数

问题描述&#xff1a; 解题思路&#xff1a; 列相乘&#xff0c;然后行相加。 注意点&#xff1a;由于元素数据范围最大为1e6&#xff0c;两个元素相乘乘积最大为1e12&#xff0c;如果元素类型为int则在乘的过程中就会爆炸&#xff0c;所以需要开long long类型。 AC代码…...

docker学习笔记3:VmWare CentOS7安装与静态ip配置

文章目录 一、安装CentOS71、下载centos镜像2、安装二、设置静态ip三、xshell连接centos本专栏的docker环境是在centos7里安装,因此首先需要会安装centos虚拟机。 本篇博客介绍如何在vm虚拟机里安装centos7。 一、安装CentOS7 1、下载centos镜像 推荐清华源,下载如下版本 …...

leetcode 547.省份数量

思路&#xff1a;dfs 或者这道题用bfs也是可以的。 这道题有点迷惑性&#xff0c;这里的数组给的是无向图的数组&#xff0c;而并不是地图&#xff0c;这里需要着重注意一下。 而后&#xff0c;这里的状态数组st没必要是二维的&#xff0c;我们并不会去遍历所给的数组&#…...

Qt5 框架学习及应用 — 对象树

Qt 对象树 对象树概念Qt为什么使用对象树 &#xff1f;将对象挂到对象树上 对象树概念 对象树&#xff1a;对于树的概念&#xff0c;相信许多学过数据结构的同学应该都不会陌生。在学习数据结构的时候我们所接触的什么二叉树、多叉树、哈夫曼树、AVL树、再到红黑树、B/B树………...

Ansible自动化运维工具---Playbook

一、playbook playbook是剧本的意思 通过 task 调用 ansible 的模块将多个 play 组织在一 个playbook中运行。 playbook本身由以下各部分组成&#xff1a; Tasks: 任务&#xff0c;即调用模块完成的某操作Variables: 变量Templates: 模板Handlers: 处理器&#xff0c;当某条…...

什么是接口和类?Java中的集合框架有哪些主要接口和类?

Java中的集合框架有哪些主要接口和类&#xff1f; Java中的集合框架&#xff08;Java Collections Framework&#xff09;提供了一套丰富的接口和类&#xff0c;用于存储和操作对象的集合。以下是Java集合框架中的主要接口和类&#xff1a; 主要接口 Collection&#xff1a; 这…...

算法学习笔记(最短路——Bellman-Ford)

B e l l m a n — F o r d Bellman—Ford Bellman—Ford是一种单源最短路径算法&#xff0c;可以用于边权为负的图&#xff0c;但是只能用于小图。 大概过程&#xff1a; 枚举每一条边&#xff0c;更新可以更新的节点&#xff08;起点到自己距离为 0 0 0&#xff0c;从地点开…...

try-catch-finally的省略与springboot

在 Java 中&#xff0c;try-catch 块是用于捕获和处理异常的结构&#xff0c;它可以帮助您在代码中处理可能发生的异常情况。在某些情况下&#xff0c;您可能希望省略 try-catch 块并将异常向上抛出&#xff0c;让调用者处理异常。这种情况通常适用于以下情况&#xff1a; 方法…...

容器Docker:轻量级虚拟化技术解析

引言 随着云计算和虚拟化技术的飞速发展&#xff0c;容器技术以其轻量级、高效、可移植的特性&#xff0c;逐渐成为了软件开发和部署的新宠。在众多容器技术中&#xff0c;Docker以其简单易用、功能强大的特点&#xff0c;赢得了广泛的关注和应用。本文将全面介绍Docker的基本概…...

windows 系统中cuda 12.1 环境安装

文章目录 1. 安装cuda 12.11.1 下载1.2 安装 cuda1.2.1 安装步骤1.2.2 环境变量安装1.3 安装cuDNN1.3.1 安装1.3.2 cuDNN配置验证2. anaconda 安装2.1 安装2.2 环境变量配置3. 报错解决1. 安装cuda 12.1 首先通过nvidia-smi 查看可以安装的CUDA最高版本...

字节和旷视提出HiDiffusion,无需训练,只需要一行代码就可以提高 SD 生成图像的清晰度和生成速度。代码已开源。

字节和旷视提出HiDiffusion&#xff0c;无需训练&#xff0c;只需要一行代码就可以提高 SD 生成图像的清晰度和生成速度。代码已开源。 支持将图像生成的分辨率提高至40964096&#xff0c;同时将图像生成速度提升1.5至6倍。 支持所有 SD 模型同时也支持 SD 模型的下游模型&…...

linux下dd制作启动U盘

dd命令是比较推荐的一种Linux环境中制作U盘启动盘的方式&#xff0c;无需安装额外的工具&#xff0c;基本上所有Linux发行版都集成了这个命令。 1、插入U盘&#xff1b; 2、打开终端&#xff1b; 3、确认U盘路径&#xff0c;在终端中输入&#xff1a;sudo fdisk -l 例如&am…...

springboot整合mybatis配置多数据源(mysql/oracle)

目录 前言导入依赖坐标创建mysql/oracle数据源配置类MySQLDataSourceConfigOracleDataSourceConfig application.yml配置文件配置mysql/oracle数据源编写Mapper接口编写Book实体类编写测试类 前言 springboot整合mybatis配置多数据源&#xff0c;可以都是mysql数据源&#xff…...

练习项目后端代码解析切面篇(Aspect)

前言 之前注解篇时我说&#xff0c;通常情况下一个自定义注解一般对应一个切面&#xff0c;虽然项目里的切面和注解个数相同&#xff0c;但是好像有一个名字看起来并不对应&#xff0c;无所谓&#xff0c;先看了再说。 ExceptionLogAspect切面 我在里面做了具体注释&#x…...

TypeScript常见面试题第六节

题目二十六:TypeScript 中的装饰器? 一、讲解视频 TS面试题二十六:TypeScript 中的可选链? 二、题目解析 本题目考察可选链的相关知识,可选链是比较新的一个语法,是一种访问嵌套对象属性的安全的方式。即使中间的属性不存在,也不会出现错误。如果可选链 ?. 前面的值为…...

LeetCode 面试经典150题 228.汇总区间

题目&#xff1a; 给定一个 无重复元素 的 有序 整数数组 nums 。 返回 恰好覆盖数组中所有数字 的 最小有序 区间范围列表 。也就是说&#xff0c;nums 的每个元素都恰好被某个区间范围所覆盖&#xff0c;并且不存在属于某个范围但不属于 nums 的数字 x 。 列表中的每个区…...

大数据分析入门10分钟快速了解SQL

SQL是什么&#xff1f; SQL全称Structured Query Language(结构化查询语言”) 为什么要用SQL&#xff1f; SQL通用 常见的表格分析操作&#xff0c;Excel也能做&#xff0c;为什么不用呢&#xff1f; 因为处理上亿行大数据时&#xff0c;Excel并不够用。 而常见的大数据引…...

设置多用户远程登录windows server服务器

##设置多用户远程登录windows server服务器 ###1、远程登录windows server 2016 运行—>mstsc—>远程IP地址—>用户和密码 2、远程windows服务器设置多用户策略 运行—>gpedit.msc->计算机配置—管理模板—windows组件—远程桌面服务—远程桌面会话主机----连…...

一文了解栈

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、栈是什么&#xff1f;二、栈的实现思路1.顺序表实现2.单链表实现3.双向链表实现 三、接口函数的实现1.栈的定义2.栈的初始化3.栈的销毁4.入栈5.出栈6.返回栈…...

C语言----汉诺塔问题

1.什么是汉诺塔问题 简单来说&#xff0c;就是有三个柱子&#xff0c;分别为A柱&#xff0c;B柱&#xff0c;C柱。其中A柱从上往下存放着从小到大的圆盘&#xff0c;我们需要借助B柱和C柱&#xff0c;将A柱上的所有圆盘转移到C柱上&#xff0c;并且一次只能移动一个圆盘&#…...

Python中驼峰命名法和下划线命名法相互转换的实战代码

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...

【hackmyvm】vivifytech靶机

渗透思路 信息收集端口扫描端口服务信息目录扫描爆破hydra--sshgit提权 信息收集 ┌──(kali㉿kali)-[~] └─$ fping -ag 192.168.9.0/24 2>/dev/null 192.168.9.119 --主机 192.168.9.164 --靶机个人习惯&#xff0c;也方便后续操作&#xff0c;将IP地址赋值给一个变…...

纯血鸿蒙APP实战开发——手写绘制及保存图片

介绍 本示例使用drawing库的Pen和Path结合NodeContainer组件实现手写绘制功能。手写板上完成绘制后&#xff0c;通过调用image库的packToFile和packing接口将手写板的绘制内容保存为图片&#xff0c;并将图片文件保存在应用沙箱路径中。 效果图预览 使用说明 在虚线区域手写…...

在什么情况下表单会被重复提交?如何避免?

表单被重复提交是Web应用中常见的问题&#xff0c;通常在用户提交表单后点击按钮多次&#xff0c;或在表单提交后刷新页面时发生。这可能导致数据的重复处理&#xff0c;比如重复记录或订单。 何时会发生表单重复提交&#xff1f; 用户多次点击提交按钮&#xff1a;在网络延迟…...

JavaScript 中的 Class 类

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 &#x1f525; 引言&#x1f3af; 基础知识&#x1f3d7;️ 构造函数 (Constructor)&#x1f510; 私有字段 (Private Fields)&#x1f510; 私有方法 (Private Methods)&#x1f9ec; 继承 (Inheritance)&#x1f4e6; 静态…...

python实验三 实现UDP协议、TCP协议进行服务器端与客户端的交互

实验三 实验题目 1、请利用生成器构造一下求阶乘的函数Factorial()&#xff0c;定义一个函数m()&#xff0c;在m()中调用生成器Factorial()生成小于100的阶乘序列存入集合s中&#xff0c;输出s。 【代码】 def factorial():n1f1while 1:​ f * n​ yield (f)​ n1…...

ServiceNow 研究:通过RAG减少结构化输出中的幻觉

论文地址&#xff1a;https://arxiv.org/pdf/2404.08189 原文地址&#xff1a;rag-hallucination-structure-research-by-servicenow 在灾难性遗忘和模型漂移中&#xff0c;幻觉仍然是一个挑战。 2024 年 4 月 18 日 灾难性遗忘&#xff1a; 这是在序列学习或连续学习环境中出现…...

ADS基础教程10-多态性(动态模型选择)

目录 一、多态性定义二、操作步骤&#xff11;.模型建立&#xff12;.模型选择&#xff13;.执行仿真 一、多态性定义 ADS中支持一个Symbol中&#xff0c;可以同时存在多个子图。在仿真时可以动态选择不同的子图继续宁仿真。 二、操作步骤 &#xff11;.模型建立 在上一章A…...

代码随想录第四十六天|单词拆分

题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09;...

RabbitMQ的介绍和使用

1.同步通讯和异步通讯 举个例子&#xff0c;同步通讯就像是在打电话&#xff0c;因此它时效性较强&#xff0c;可以立即得到结果&#xff0c;但如果你正在和一个MM打电话&#xff0c;其他MM找你的话&#xff0c;你们之间是不能进行消息的传递和响应的 异步通讯就像是微信&#…...

前端get请求日期类型参数向后端传参失败

1、背景 get请求&#xff0c;通过url上传参&#xff0c;因此日期类型是string类型数据 2、异常信息 nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.time.LocalDate] for…...

【docker 】 push 镜像提示:denied: requested access to the resource is denied

往 Docker Registry &#xff08;私服&#xff09;push 镜像提示&#xff1a;denied: requested access to the resource is denied 镜像push 语法&#xff1a;docker push <registry-host>:<registry-port>/<repository>:<tag> docker push 192.16…...

浏览器各类好用插件使用及常见问题(技巧)总结

目录 Vimium C快捷键问题为什么Vimium C - 全键盘操作浏览器插件在百度页面中, x ,o,f等快捷键不起作用如何使用viminum c插件进行自定义快捷键?vimucm 为什么在浏览器首页时快捷键不起作用? 网页截图问题firefox 网页截图使用 idm问题浏览器点击idm 不下载? 待续、更新中 V…...

Python批量计算多张遥感影像的NDVI

本文介绍基于Python中的gdal模块&#xff0c;批量基于大量多波段遥感影像文件&#xff0c;计算其每1景图像各自的NDVI数值&#xff0c;并将多景结果依次保存为栅格文件的方法。 如下图所示&#xff0c;现在有大量.tif格式的遥感影像文件&#xff0c;其中均含有红光波段与近红外…...

6.k8s中的secrets资源

一、Secret secrets资源&#xff0c;类似于configmap资源&#xff0c;只是secrets资源是用来传递重要的信息的&#xff1b; secret资源就是将value的值使用base64编译后传输&#xff0c;当pod引用secret后&#xff0c;k8s会自动将其base64的编码&#xff0c;反编译回正常的字符…...

git 更换远程仓库地址三种方法总结

git 更换远程仓库地址三种方法总结 一、前言 由于私服的 gitlab 的地址变更&#xff0c;导致部分项目代码提交不上去&#xff0c;需要修改远端仓地址。 其它需要修改远程仓地址的情况如&#xff1a;切换git clone 协议由ssh变为https。 二、环境 windows 10git version 2.3…...

快速找出存(不存在)在某个(或多个)文件的文件夹

首先&#xff0c;需要用到的这个工具&#xff1a; 度娘网盘 提取码&#xff1a;qwu2 蓝奏云 提取码&#xff1a;2r1z 想要找出有下面这个文件存在的文件夹 切换到批量文件复制版块&#xff0c;快捷键Ctrl5 右侧&#xff0c;搜索添加 选定范围&#xff0c;勾选搜索文件夹、包…...

Linux USB转串口设备路径的查找方法

1、USB转串口设备 USB转串口设备是在嵌入式软件开发过程中经常要使用的&#xff0c;常常用于对接各种各样的串口设备。如果一台linux主机上使用多个usb转串口设备时&#xff0c;应用程序中就需要知道自己操作的是哪个串口设备。串口设备在系统上电时&#xff0c;由于驱动加载的…...

【初阶数据结构】单链表之环形链表

目录标题 前言环形链表的约瑟夫问题环形链表环形链表|| 前言 前面我们已经学习了关于单链表的一些基本东西&#xff0c;今天我们来学习单链表的一个拓展——环形链表&#xff0c;我们将用力扣和牛客网上的三道题目来分析讲解环形链表问题。 环形链表的约瑟夫问题 我们首先来看…...

【积分,微分,导数,偏导数公式推导】

1. 积分 积分是微积分的一个分支&#xff0c;用于计算曲边梯形的面积或者变速直线运动的总距离等。积分分为不定积分和定积分。 不定积分&#xff1a;给出一个函数&#xff0c;求出其所有可能的原函数。定积分&#xff1a;计算一个函数在特定区间上的积分。 2. 微分 微分是…...

java:递归实现的案例

//求第20个月兔子的对数 //每个月兔子对数&#xff1a;1&#xff0c;1&#xff0c;2&#xff0c;3&#xff0c;5&#xff0c;8 public class Test {//求第20个月兔子的对数//每个月兔子对数&#xff1a;1&#xff0c;1&#xff0c;2&#xff0c;3&#xff0c;5&#xff0c;8pu…...