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,所以这个对象可以被销毁了。// 循环引用问题也就避免了
}

在这里插入图片描述

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

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

相关文章

仓库管理员如何入门?仓库管理六大步骤教会你!

新手菜鸟入行&#xff0c;如何做好一个仓库管理员&#xff1f;仓库运营对于许多行业至关重要&#xff0c;例如制造、零售和物流。它们涉及高效、安全地接收、仓储、拣选、包装和运输货物。 跟着这6个步骤做&#xff0c;最慢一个月&#xff0c;最快一周&#xff0c;就能轻松做好…

高效项目管理:如何利用zz-plan在线甘特图工具

作为项目管理人员&#xff0c;使用 zz-plan https://zz-plan.com/这样的在线甘特图协作软件可以极大地提高项目管理的效率和效果。以下是结合zz-plan特点的一些关键步骤&#xff1a; 1. 制定项目计划 在zz-plan上创建新的项目&#xff0c;定义项目目标、关键里程碑和最终期限。…

ABB RobotStudio学习记录(一)新建工作站

RobotStudio新建工作站 最近遇到 虚拟示教器和 Rapid 代码不能控制 视图中机械臂的问题&#xff0c;其实是由于机械臂和工作站不匹配。以下是解决方法。 名称版本Robot Studio6.08 新建一个”空工作站“&#xff1b; 在目标位置新建一个目标文件夹 C:\solution\test&#xff0…

数据挖掘实战-基于深度学习RNN+CNN的能源价格预测模型

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

深入理解 LinkedList 及底层源码分析

LinkedList 是基于链表结构的一种 List&#xff0c;在分析 LinkedList 源码前我们先对对链表结构做一个简单的了解。 一、链表的概念 链表是由一系列非连续的节点组成的存储结构&#xff0c;简单分下类的话&#xff0c;链表又分为_单向链表和双向链表&#xff0c;而单向 / 双…

layui 数据表格 拖动 列、行 位置 重新排序 等

先贴官网 layui官网 &#xff1b; 再贴一个要使用的 插件官网 &#xff1a; layui-soul-table 示例文档 &#xff1b; 这个插件功能很多 看到那个下载 后悔没早点知道啊 还自己写了 一个下载 可以到官网看看 很多实用的 需要引入的 js layui.config({base: rootPath…

检测服务器环境,实现快速部署。适用于CRMEB_PRO/多店

运行效果如图&#xff1a; 最近被好多人问&#xff0c;本来运行的好好的&#xff0c;突然swoole就启动不了了。 本工具为爱发电&#xff0c;如果工具正好解决了您的需求。我会很开心 代码如下&#xff1a; """本脚本为爱发电by:网前雨刮器 """…

如何翻译外文文献【攻略】

如何翻译外文文献【攻略】 前言版权推荐如何翻译外文文献简单描述第一步 准备一篇外文文献第二步 翻译网站第三步 解锁文档第四步 编辑dpf第五步 pdf转为word第六步 编辑word第七步 word转为pdf 最后 前言 2024-5-7 14:50:14 以下内容源自《【攻略】》 仅供学习交流使用 版权…

【全网首发】Typecho文章采集器火车头插件去授权版

内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 三、学习资料下载 一、详细介绍 目前市面上基本没有typecho火车头采集器 而分享的这一款采集器&#xff0c;牛的一批 内置使用方法与教程&#xff01; 二、效果展示 1.部分代码 代码如下&#xff08;示例&#…

串的模式匹配之KMP算法实现

概述 函数刻画 主串位置不变&#xff0c;next值就是模式串(子串)比较后应跳转的位置 不同位置 next[j]函数 next由模式串决定&#xff0c;看模式串当前比较位的前串中前后缀相同的个数来得k-1的值&#xff0c;next[当前位]k1 小补充 PM值&#xff1a;也称部分匹配值&#xf…

Redis Cluster on K8s 大揭密

之前我们针对 Redis 容器化&#xff0c;做了一些讨论&#xff1a; 《Redis 容器化&#xff0c;是不是个“软柿子”》&#xff0c;业界不乏相关的实践分享&#xff0c;KubeBlocks 也针对 Redis Cluster 做了适配并有对应的解决方案。在 Redis 容器化的过程中&#xff0c;KubeBlo…

【学习AI-相关路程-工具使用-NVIDIA SDK MANAGER==NVIDIA-jetson刷机工具安装使用 】

【学习AI-相关路程-工具使用-NVIDIA SDK manager-NVIDIA-jetson刷机工具安装使用 】 1、前言2、环境配置3、知识点了解&#xff08;1&#xff09;jetson 系列硬件了解&#xff08;2&#xff09;以下大致罗列jetson系列1. Jetson Nano2. Jetson TX23. Jetson Xavier NX4. Jetson…

YouTube广告全教学:形式、投放步骤与技巧(2024年更新)

YouTube作为全球最大的视频分享和观看平台吸引了大量的观众&#xff0c;这一平台以其无与伦比的用户参与度和覆盖范围&#xff0c;重新定义了人们获取与分享知识的方式&#xff0c;同时也为企业开辟了一片前所未有的营销蓝海。 据统计&#xff0c;全球观众平均每天观看 YouTub…

超疏水TiO₂纳米纤维网膜的良好性能

超疏水TiO₂纳米纤维网膜是一种具有特殊性能的材料&#xff0c;它结合了TiO₂的光催化性能和超疏水表面的自清洁、防腐、防污等特性。这种材料在防水、自清洁、油水分离等领域具有广阔的应用前景。 制备超疏水TiO₂纳米纤维网膜的过程中&#xff0c;通过精确控制纺丝溶液的成分…

揭秘前端开发的“薪”机遇

众所周知&#xff0c;华为开发者大会2023&#xff0c;宣布不再兼容安卓&#xff0c;同时宣布了“鸿飞计划”&#xff0c;欲与iOS、安卓在市场三分天下&#xff0c;这对中国国产操作系统而言&#xff0c;具有划时代的意义。 最近有不少前端的开发者来咨询鸿蒙开发&#xff0c;今…

OpenNJet : 下一代云原生应用引擎

本心、输入输出、结果 文章目录 OpenNJet &#xff1a; 下一代云原生应用引擎前言OpenNJet 技术架构安装 OpenNJet为什么有了 OpenNJetOpenNJet 和 NGINX 是什么关系什么是云原生应用引擎&#xff1f;OpenNJet 的有哪些优势OpenNJet 的有哪些优势 OpenNJet 与国产化OpenNJet 使…

Llama 3 超级课堂

https://github.com/SmartFlowAI/Llama3-Tutorial/tree/main 第一节作业 streamlit run web_demo.py /root/share/new_models/meta-llama/Meta-Llama-3-8B-Instruct

一键静音,iPhone勿扰模式助你远离干扰

在现代社会的快节奏生活中&#xff0c;我们时常被各种各样的通知、铃声和提示音所打扰&#xff0c;无法专注地工作或享受宁静的时光。而iPhone的勿扰模式功能&#xff0c;就像是一位贴心的助手&#xff0c;能够一键帮你屏蔽这些干扰&#xff0c;让你在需要的时候拥有一个清静的…

窃鈇逃债,赧然惭愧——“天下共主”周赧王的结局

引子&#xff0c;债台高筑 周赧王五十九年&#xff08;前256年&#xff09;&#xff0c;雒邑王都内&#xff0c;大周第三十七代天子、年近八十的周赧王姬延困坐在王宫内的高台上&#xff0c;愁容满面、沮丧悲切、束手无策&#xff1b;而王宫宫墙外不远处&#xff0c;是一大帮举…

流畅的python-学习笔记_设计模式+装饰器+闭包

策略模式 类继承abc.ABC即实现抽象类&#xff0c;方法可用abc.abstractmethod装饰&#xff0c;表明为抽象方法 装饰器基础 装饰器实际是语法糖&#xff0c;被装饰的函数实际是装饰器内部返回函数的引用 缺点&#xff1a;装饰器函数覆盖了被装饰函数的__name__和__doc__属性…