新闻详情

新闻详情

首页 / 资讯中心 / 详情

【Rust入门知识点学与练】第18课:智能指针 Smart Pointers

发布时间:2026/9/6 8:29:29来源:尧图网络
【Rust入门知识点学与练】第18课:智能指针 Smart Pointers
知识点1Box — 堆上分配Box 把数据放在堆上栈上只存一个指针fnmain(){// 在堆上分配一个整数letboxedBox::new(42);println!(值: {},boxed);// 42println!(解引用: {},*boxed);// 42* 解引用// 在堆上分配一个字符串letsBox::new(String::from(hello));println!(字符串: {},s);// Box 最常见的用途递归类型// 编译器不知道递归类型的大小用 Box 包装后大小就确定了#[derive(Debug)]enumList{Cons(i32,BoxList),// 一个节点值 指向下一个节点的指针Nil,// 空节点链表结尾}letlistList::Cons(1,Box::new(List::Cons(2,Box::new(List::Cons(3,Box::new(List::Nil))))));println!(链表: {:?},list);}知识点2Deref trait 和解引用Box 实现了 Deref trait所以可以自动解引用fnmain(){letboxedBox::new(5);// 手动解引用assert_eq!(5,*boxed);// 自动解引用函数参数是 i32传入 Boxi32 也能工作fntakes_ref(x:i32){println!(收到: {},x);}takes_ref(boxed);// ✅ 自动解引用 Boxi32 - i32// 解引用强制转换Deref Coercion// String 实现了 DerefTarget str// 所以 String 可以自动转为 strletsBox::new(String::from(hello));fntakes_str(s:str){println!(字符串: {},s);}takes_str(s);// ✅ BoxString - String - str// 自定义类型实现 DerefstructMyBoxT(T);implTMyBoxT{fnnew(x:T)-MyBoxT{MyBox(x)}}implTstd::ops::DerefforMyBoxT{typeTargetT;fnderef(self)-T{self.0}}letmbMyBox::new(42);println!(MyBox 值: {},*mb);// 42自动解引用}知识点3Drop trait — 清理资源当值离开作用域时自动调用 dropstructCustomSmartPointer{data:String,}implDropforCustomSmartPointer{fndrop(mutself){println!(清理: {} 被销毁了,self.data);}}fnmain(){letaCustomSmartPointer{data:String::from(第一个)};letbCustomSmartPointer{data:String::from(第二个)};println!(创建完成);// 可以用 drop 函数提前释放drop(a);// 手动提前释放 aprintln!(a 已被释放);// b 在这里自动释放}// 输出:// 创建完成// 清理: 第一个 被销毁了// a 已被释放// 清理: 第二个 被销毁了知识点4Rc — 多所有权引用计数RcReference Counted允许多个所有者共享同一份数据usestd::rc::Rc;fnmain(){letaRc::new(String::from(共享数据));println!(引用计数: {},Rc::strong_count(a));// 1letbRc::clone(a);// 增加引用计数不是深拷贝println!(引用计数: {},Rc::strong_count(a));// 2{letcRc::clone(a);println!(引用计数: {},Rc::strong_count(a));// 3println!(c 读到: {},c);// c 在这里被释放引用计数 -1}println!(引用计数: {},Rc::strong_count(a));// 2// 多个所有者共享同一个数据letdataRc::new(vec![1,2,3,4,5]);letowner1Rc::clone(data);letowner2Rc::clone(data);println!(owner1: {:?},owner1);println!(owner2: {:?},owner2);println!(引用计数: {},Rc::strong_count(data));// 3}知识点5RefCell — 内部可变性RefCell 允许在持有不可变引用时修改内部数据运行时检查借用规则usestd::cell::RefCell;fnmain(){letdataRefCell::new(vec![1,2,3]);// borrow() 返回不可变借用println!(数据: {:?},data.borrow());// borrow_mut() 返回可变借用data.borrow_mut().push(4);println!(修改后: {:?},data.borrow());// ⚠️ 运行时检查借用规则// 如果同时存在 borrow 和 borrow_mut程序会 panic// let r1 data.borrow();// let r2 data.borrow_mut(); // ❌ panic! 同时存在不可变和可变借用// 配合 Rc 使用多个所有者共享可变数据usestd::rc::Rc;letshared_dataRc::new(RefCell::new(vec![1,2,3]));letowner1Rc::clone(shared_data);letowner2Rc::clone(shared_data);owner1.borrow_mut().push(4);println!(owner2 看到: {:?},owner2.borrow());// [1, 2, 3, 4]}知识点6组合使用 Rcusestd::rc::Rc;usestd::cell::RefCell;// 用 RcRefCellT 实现一个共享的可变计数器structCounter{count:RefCellu32,}implCounter{fnnew()-Self{Counter{count:RefCell::new(0),}}fnincrement(self){*self.count.borrow_mut()1;}fnget(self)-u32{*self.count.borrow()}}fnmain(){letcounterRc::new(Counter::new());// 多个所有者共享同一个计数器letc1Rc::clone(counter);letc2Rc::clone(counter);c1.increment();c1.increment();c2.increment();println!(计数: {},counter.get());// 3println!(引用计数: {},Rc::strong_count(counter));// 3}核心规则智能指针 用途 所有权 可变性Box 堆分配、递归类型 单一所有权 可变/不可变Rc 多所有权共享 共享所有权 仅不可变RefCell 内部可变性 单一所有权 运行时检查RcRefCell 共享 可变 共享所有权 运行时检查检查时机 说明Box / Rc 编译时检查借用规则RefCell 运行时检查违反则 panic动手试试补全下面的代码usestd::rc::Rc;usestd::cell::RefCell;// 补全定义一个 Student 结构体// 字段name: String, grades: RefCellVecf64// 补全为 Student 实现以下方法// 1. new(name: String) - Student// 2. add_grade(self, grade: f64) 添加成绩// 3. average(self) - f64 计算平均分无成绩返回 0.0// 4. highest(self) - Optionf64 最高分// 5. display(self) - String 格式: 学生: 名字, 成绩: [x, y, z], 平均: x.xxfnmain(){// 补全创建一个学生 张三用 Rc 包装// 创建两个共享引用 s1 和 s2// 补全通过 s1 添加成绩 85.0, 92.0, 78.0// 通过 s2 添加成绩 95.0// 补全通过原始引用打印学生信息// 期望输出: 学生: 张三, 成绩: [85, 92, 78, 95], 平均: 87.50// 补全打印最高分// 期望输出: 最高分: Some(95)// 补全打印引用计数// 期望输出: 引用计数: 3}期望输出学生: 张三, 成绩: [85, 92, 78, 95], 平均: 87.50最高分: Some(95)引用计数: 3写好了贴过来没问题就进入第19课并发 Concurrency 贴代码usestd::rc::Rc;usestd::cell::RefCell;// Student结构体定义structStudent{name:String,grades:RefCellVecf64,}implStudent{// 1. 构造函数fnnew(name:String)-Student{Student{name,grades:RefCell::new(Vec::new()),}}// 2. 添加成绩self不可变引用借助RefCell实现内部可变性fnadd_grade(self,grade:f64){self.grades.borrow_mut().push(grade);}// 3. 平均分无成绩返回0.0fnaverage(self)-f64{letgradesself.grades.borrow();ifgrades.is_empty(){return0.0;}letsum:f64grades.iter().sum();sum/(grades.len()asf64)}// 4. 最高分返回Optionf64fnhighest(self)-Optionf64{letgradesself.grades.borrow();grades.iter().copied().max_by(|a,b|a.partial_cmp(b).unwrap())}// 5. 格式化输出字符串fndisplay(self)-String{letgradesself.grades.borrow();format!(学生: {}, 成绩: {:?}, 平均: {:.2},self.name,grades,self.average())}}fnmain(){// 创建Rc包裹的学生对象letstudentRc::new(Student::new(String::from(张三)));lets1Rc::clone(student);lets2Rc::clone(student);// 通过不同共享引用添加成绩RefCell实现内部可变性s1.add_grade(85.0);s1.add_grade(92.0);s1.add_grade(78.0);s2.add_grade(95.0);// 打印学生信息println!({},student.display());// 打印最高分println!(最高分: {:?},student.highest());// 获取Rc当前引用计数println!(引用计数: {},Rc::strong_count(student));}运行输出plaintext学生: 张三, 成绩: [85.0, 92.0, 78.0, 95.0], 平均: 87.50最高分: Some(95.0)引用计数: 3核心知识点讲解Rc RefCellRust高频组合1. Rc 单线程共享所有权Rc::new 在堆上创建对象Rc::clone() 增加引用计数只是复制指针不复制底层数据Rc::strong_count() 查看当前强引用的数量Rc是单线程专用多线程需要 Arc 。2. RefCell内部可变性正常情况下 self 不可变引用不能修改结构体字段RefCell 绕开这个限制实现内部可变性.borrow() 获取不可变借用.borrow_mut() 获取可变借用RefCell在运行时检查借用规则而不是编译期违反借用规则程序会panic。3. Rc 黄金组合多个所有者Rc 运行时内部可变性RefCell多个共享引用可以修改同一份数据本题 s1 和 s2 都能添加成绩。4. highest 里面的细节grades.iter().copied().max_by(|a,b|a.partial_cmp(b).unwrap())f64没有实现Ord存在NaN不能直接用.max()要用 partial_cmp 。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

咸阳陕西墙面翻新选择时需要注意什么:判断基层是否需要铲除至红砖的指南 2026/9/6 9:14:35

咸阳陕西墙面翻新选择时需要注意什么:判断基层是否需要铲除至红砖的指南

陕西墙面翻新选择时需要注意什么:判断基层是否需要铲除至红砖,核心在于先通过划痕测试和空鼓面积检查来确定基层状况。如果旧墙表面有起砂、空鼓或疏松层,必须铲除至红砖层;反之,若基层强度足够且无空鼓,则…

阅读更多 →
无sudo环境下编译运行RIOT 2026.07:native模式吞吐量测试实践 2026/9/6 9:14:35

无sudo环境下编译运行RIOT 2026.07:native模式吞吐量测试实践

在无 sudo 的系统上跑物联网操作系统,听起来像是给自己找麻烦,但真遇到这种环境时,只能想方设法把事办成。我这次在一台 Ubuntu 主机上,没有任何管理员权限、也几乎没额外安装任何系统依赖,把 RIOT 2026.07 编译起来&a…

阅读更多 →
LlamaFactory微调实战:LoRA/QLoRA参数调优与避坑指南 2026/9/6 9:14:35

LlamaFactory微调实战:LoRA/QLoRA参数调优与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
基于Python和Vue3的校园学科竞赛管理系统开发实践 2026/9/6 9:14:35

基于Python和Vue3的校园学科竞赛管理系统开发实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
通达信基本面副图指标源码详解:用FINANCE函数构建股票评分卡 2026/9/6 9:14:35

通达信基本面副图指标源码详解:用FINANCE函数构建股票评分卡

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
Stable Diffusion模型实战:忧郁小红帽AI绘画的情绪表达技术解析 2026/9/6 9:11:35

Stable Diffusion模型实战:忧郁小红帽AI绘画的情绪表达技术解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞