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

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

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

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

场景1:共享数据

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

rust 复制代码
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 的出现解决了这个问题,让共享变得可能:

rust 复制代码
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 所指向的数据会导致编译错误:

rust 复制代码
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 所指向的数据:

rust 复制代码
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),则会导致循环引用,使内存无法释放:

rust 复制代码
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 可以避免这种情况,彼此联系不会持有强引用:

rust 复制代码
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:弱引用,防止循环引用带来的内存泄漏。
相关推荐
青柠之夏cc5 小时前
前端拖拽功能原生实现,不引入拖拽库完成业务
开发语言·前端·python
滕州市燕猫虎计算机科技工作室个体工商户5 小时前
《Rust程序设计》学习笔记三
rust·学习笔记·rust程序设计
ym hyd 1115 小时前
题库建立与考试系统源码 Java+SpringBoot+Vue3 前后分离
java·开发语言·vue.js·spring boot·毕设
OKkankan6 小时前
Python 高阶语法(一):高阶函数、闭包、lambda 与 functools——从底层真正理解装饰器
开发语言·python
geovindu6 小时前
rust: Facade Pattern
开发语言·后端·设计模式·rust·外观模式
福大大架构师每日一题6 小时前
Rust 1.99.0发布:C 可变参数、裸函数、Cargo 配置、Rustdoc 性能与大量兼容性调整全解析
c语言·开发语言·rust
智鸟科技GemeOpen开发者智能设备6 小时前
平安校园 AI 智能实时告警系统 智鸟科技·GemeOpen + 谷华科技·融合创新方案白皮书
java·开发语言·python·物联网·智能家居
Wang's Blog6 小时前
Java框架 SpringCloud 快速入门: Feign 的自定义配置与日志级别
java·开发语言·spring cloud
成旭先生6 小时前
企业全景信息查询 API:工商照面 33 项、股东出资、变更与社保一次查全
java·开发语言·api接口·企业信息查询·工商数据·风控尽调·供应商准入
2601_962885726 小时前
批量取数比循环单取快多少?用 AlphaFeed klines.batch给多股票取数提速
开发语言·php·batch