恋爱脑学Rust之智能指针Rc,RefCell和Weak指针

news2024/12/27 13:04:19

在这里插入图片描述

小明和小丽为了维系彼此的关系,一起探索了智能指针的奥秘。通过 RcRefCellWeak 的帮助,他们得以克服情感中遇到的种种困境。

第一章:Rc 智能指针的共生

小明和小丽搬进了一个共同的小屋,他们彼此相爱,决定共用一个拥有自己专属家具的房间。用 Rc 类型来表达这一关系,它是一个引用计数智能指针,可以让多个持有者安全地共享数据。

场景1:共享数据

假如在这个故事中,我们没有 Rc 这样的支持,那么如果小明和小丽都需要访问同一个房间的家具(Room),会导致所有权冲突:

struct Room {
    furniture: String,
}

fn main() {
    let shared_room = Room {
        furniture: String::from("Shared Bed"),
    };

    // 如果不使用 Rc,无法让两个变量共享同一个 Room
    let ming_room = shared_room; // 转移所有权到 ming_room
    let li_room = shared_room; // 报错:无法重复所有权
}

这个错误正如小明和小丽无法同时拥有同一个家具一样。Rc 的出现解决了这个问题,让共享变得可能:

use std::rc::Rc;

struct Room {
    furniture: String,
}

fn main() {
    // 使用 Rc 实现共享房间
    let shared_room = Rc::new(Room {
        furniture: String::from("Shared Bed"),
    });

    let ming_room = Rc::clone(&shared_room); // 克隆 Rc 增加引用计数
    let li_room = Rc::clone(&shared_room);

    println!("Ming's furniture: {}", ming_room.furniture);
    println!("Li's furniture: {}", li_room.furniture);
}
解释

Rc 允许小明和小丽共享房间,而不会因为一个人拿走所有权而导致另一个人无法访问。

第二章:RefCell 智能指针的理解与沟通

在相处的过程中,小明发现他们的房间(即数据)需要在某些时候进行修改,而 Rc 默认是只读的。于是 RefCell 出现了,这种智能指针允许在运行时执行可变借用检查。它就像他们的沟通桥梁,确保修改安全。

场景2:内部可变性

在没有 RefCell 时,试图修改 Rc 所指向的数据会导致编译错误:

use std::rc::Rc;

struct Room {
    furniture: String,
}

fn main() {
    let shared_room = Rc::new(Room {
        furniture: String::from("Shared Bed"),
    });

    // 无法直接修改 Rc 所指向的数据
    shared_room.furniture = String::from("New Bed"); // 错误
}

但是 RefCell 允许我们内部修改 Rc 所指向的数据:

use std::rc::Rc;
use std::cell::RefCell;

struct Room {
    furniture: RefCell<String>,
}

fn main() {
    let shared_room = Rc::new(Room {
        furniture: RefCell::new(String::from("Shared Bed")),
    });

    // 使用 borrow_mut() 修改 RefCell 内部的数据
    *shared_room.furniture.borrow_mut() = String::from("New Bed");

    println!("Updated furniture: {}", shared_room.furniture.borrow());
}
解释

在这个故事中,RefCell 为小明和小丽提供了沟通方式,避免了访问冲突,确保他们可以顺利商讨并更新房间的布置。

第三章:Weak 智能指针的回忆与淡忘

随着时间的推移,小明和小丽的爱情逐渐淡去,他们的联系变成了不再紧密的弱引用Weak 可以让他们保留彼此的联系,但不会增加引用计数,防止循环引用带来的内存泄漏。

场景3:避免循环引用

假如小明和小丽各自对彼此的联系是强引用(Rc),则会导致循环引用,使内存无法释放:

use std::rc::Rc;
use std::cell::RefCell;

struct Person {
    name: String,
    partner: Rc<RefCell<Option<Rc<Person>>>>,
}

fn main() {
    let ming = Rc::new(Person {
        name: String::from("Ming"),
        partner: RefCell::new(None),
    });
    let li = Rc::new(Person {
        name: String::from("Li"),
        partner: RefCell::new(Some(Rc::clone(&ming))),
    });
    
    *ming.partner.borrow_mut() = Some(Rc::clone(&li));

    // 错误:相互的 Rc 循环引用导致内存无法回收
}

这里,Weak 可以避免这种情况,彼此联系不会持有强引用:

use std::rc::{Rc, Weak};
use std::cell::RefCell;

struct Person {
    name: String,
    partner: RefCell<Option<Weak<Person>>>,
}

fn main() {
    let ming = Rc::new(Person {
        name: String::from("Ming"),
        partner: RefCell::new(None),
    });
    let li = Rc::new(Person {
        name: String::from("Li"),
        partner: RefCell::new(Some(Rc::downgrade(&ming))),
    });
    
    *ming.partner.borrow_mut() = Some(Rc::downgrade(&li));

    // 使用 Weak 指针,不会增加引用计数
    println!("Ming's partner: {:?}", ming.partner.borrow().as_ref().unwrap().upgrade());
}
解释

Weak 就像一份美好的回忆,它不会真正占据内存,避免了循环引用导致的内存泄漏,同时也能提供必要的联系。

总结

  • Rc:提供共享的强引用,用于安全共享的场景。
  • RefCell:内部可变性,解决运行时的可变借用问题。
  • Weak:弱引用,防止循环引用带来的内存泄漏。

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

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

相关文章

Matlab车牌识别课程设计报告(附源代码)

Matlab车牌识别系统 分院&#xff08;系&#xff09; 信息科学与工程 专业 学生姓名 学号 设计题目 车牌识别系统设计 内容及要求&#xff1a; 车牌定位系统的目的在于正确获取整个图像中车牌的区域&#xff0c; 并识别出车牌号。通过设计实现车牌识别系…

Java 文件操作与IO流

文件 文件有两个概念&#xff0c;在广义来看就是操作系统上对硬件和软件资源抽象为文件。 在侠义上来看&#xff0c;就是我们保存在硬盘上的文件 在这里我们讨论的是狭义的文件&#xff0c;在外面的硬盘上的文件细分又可以分为二进制文件和文本文件&#xff0c;文本文件可以通…

C++ 优先算法 —— 有效三角形的个数(双指针)

目录 题目&#xff1a;有效三角形个数 1. 题目解析 2. 算法原理 解法一&#xff1a; 暴力枚举 解法二&#xff1a; 双指针算法 3. 代码实现 暴力枚举 双指针算法 题目&#xff1a;有效三角形个数 1. 题目解析 题目截图&#xff1a; 题目的意思就是在一个数组中&#x…

前端拖拽库方案之react-beautiful-dnd

近期&#xff0c;知名 React 拖拽库 react-beautiful-dnd 宣布了项目弃用的决定&#xff0c;未来将不再维护。这一决定源于其存在的缺陷与局限性&#xff0c;促使作者转向开发一个更加现代化的拖拽解决方案——Pragmatic drag and drop&#xff08;下面会介绍&#xff09;&…

《高频电子线路》—— 调制

文章内容来源于【中国大学MOOC 华中科技大学通信&#xff08;高频&#xff09;电子线路精品公开课】&#xff0c;此篇文章仅作为笔记分享。 调制 调制的原因 第一个原因 是为了要做出切实可行的天线。 无线电波能够从天线发射出去&#xff0c;以及正常的接收&#xff0c;需要…

第二十四章 v-model原理及v-model简化表单类组件封装

目录 一、v-model 原理 二、表单类组件封装 三、v-model简化组件封装代码 一、v-model 原理 原理&#xff1a;v-model本质上是一个语法糖。例如应用在输入框上&#xff0c;就是 value属性 和 input事件 的合写。 作用&#xff1a;提供数据的双向绑定 ① 数据变&#x…

机器学习中的数据可视化:常用库、单变量图与多变量图绘制方法

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

SELS-SSL/TLS

一、了解公钥加密&#xff08;非对称加密&#xff09; 非对称加密中&#xff0c;用于加密数据的密钥与用于解密数据的密钥不同。私钥仅所有者知晓&#xff0c;而公钥则可自由分发。发送方使用接收方的公钥对数据进行加密&#xff0c;数据仅能使用相应的私钥进行解密。 你可以将…

Kubernetes中的secrets存储

华子目录 2.secrets2.1secrets功能介绍2.2secrets的创建2.2.1从文件创建2.2.2编写yaml文件 2.3secret的使用案例2.3.1将secret挂载到volume中2.3.2设置子目录映射secret密钥2.3.3将secret设置为环境变量2.3.4存储docker register的认证信息spec.imagePullSecrets[] 2.secrets …

软件设计师笔记-数据结构

数据结构 数据元素的集合及元素间的相互关系和构造方法。 线性表的存储结构 顺序存储链式存储 单链表节点 typedef struct node { int data; struct node *link; }NODE, *LinkList; 双向链表 每个节点有两个指针&#xff0c;分别指出直接前驱和直接后继。 循环链表 尾…

「Mac畅玩鸿蒙与硬件22」鸿蒙UI组件篇12 - Canvas 组件的动态进阶应用

在鸿蒙应用中,Canvas 组件可以实现丰富的动态效果,适合用于动画和实时更新的场景。本篇将介绍如何在 Canvas 中实现动画循环、动态进度条、旋转和缩放动画,以及性能优化策略。 关键词 Canvas 组件动态绘制动画效果动态进度条旋转和缩放性能优化一、使用定时器实现动画循环 …

通俗易懂的理解递归 回溯 DFS

文章目录 递归概念递归例子1&#xff1a;递归打印链表递归例子2&#xff1a;求n数之和 回溯概念回溯例子1&#xff1a;组合问题 DFS概念DFS例子1&#xff1a;不同路径DFS例子2&#xff1a;岛屿数量总结 递归 概念 “方法自己调用自己&#xff0c;每一次调用都会更加接近递归的…

【AD】1-7 AD24软件扩展插件的设置与安装

1.如图所示打开扩展 2.点击齿轮后&#xff0c;确保离线安装位置关联了软件安装包的路径位置后&#xff0c;进行勾选选择后&#xff0c;点击应用即可安装。 注意&#xff1a;如果位置关联错误&#xff0c;则显示如图

Window on ARM解锁所有的TTS语音包供python调用

Window on ARM解锁所有的TTS语音包供python调用 可用的语音包查看查看TTS可用的语音包解锁语音包设置升级系统打开注册表导出注册表修改注册表导入新的注册表可用的语音包查看 微软的Windows 10操作系统为设备上安装的每种语言提供了一套语音。但只有部分已安装的语音能在整个…

pandas数据处理高级系列003---什么是交叉表(Cross Tabulation)以及pandas如何生成

做ab测试的时候遇到了一个新的知识点&#xff0c;交叉表以及如何用pandas生成交叉表 交叉表&#xff08;Cross Tabulation&#xff09;&#xff0c;也称为列联表&#xff08;Contingency Table&#xff09;&#xff0c;是一种用于统计分析的表格&#xff0c;用于显示两个或多个…

MySQL数据库之存储过程的创建与应用

存储过程 procedure 一.存储过程 作用&#xff1a;将经常使用的功能写成存储过程&#xff0c;方便后续重复使用。 二.创建存储过程 三.调用存储过程 call在计算机中是调用的意思 案例1&#xff1a;查看MySQL用户数 如上图所示&#xff0c;这是查看MySQL数据库中的user个数…

手搓简易shell

1.打印命令行 &#xff0c;接受命令行输入 命令行就是&#xff0c;“[用户名主机名 当前目录]$"获取这些信息都存储在Linux内核中的环境变量中&#xff0c;用getenv()函数取出 #include <stdio.h>2 #include <stdlib.h>3 #include <string.h>4 #include…

多个JDK版本之间的切换

首先电脑上可以同时安装多个版本的 JDK&#xff08;Java Development Kit),因为不同的应用程序可能需要不同 Java 版本的支持,安装多个 JDK 版本并不会导致冲突&#xff0c;只要设置好即可,在不同的情况下切换不同的jdk版本保证程序正常工作 很多程序jdk8 已经不支持,所以下载…

鸿蒙生态下开发挑战-鸿蒙低代码开发工具展望及优势

鸿蒙生态下开发挑战 在鸿蒙生态下开发时&#xff0c;开发者可能会遇到多方面的挑战&#xff0c;这些挑战主要涉及开发工具、技术难度、生态竞争以及市场定位等方面。以下是对这些挑战的详细分析&#xff1a; 一、开发工具不完善 尽管鸿蒙系统的开发工具DevEco Studio在逐步完…