Rust 教程笔记
官方文档
官网
登录
介绍安装
规则命令
基本语法
智能指针
VEITOOL文档系统
智能指针
在 Rust 中,智能指针(Smart Pointers)是一类特殊的指针类型,提供了比普通引用(如 &T)更多的功能,通常用于管理内存、控制生命周期或实现特定行为。智能指针通过结构体实现,并通常通过实现 Deref 和 Drop 等 trait 来提供类似指针的行为和额外的功能。 一、智能指针的概述1. 什么是智能指针?智能指针是一个封装了数据的结构体,拥有对数据的引用或所有权,并通过特定的逻辑管理数据的生命周期或访问方式。 智能指针通常用于:内存管理:如自动释放内存(`Box
`, `Rc
`, `Arc
`)。 资源管理:如管理文件句柄、网络连接等。 自定义行为:如实现延迟初始化、引用计数或所有权控制。 与普通引用不同,智能指针通常拥有数据的所有权,并可能在析构时执行特定逻辑(如释放内存)。 2. Rust 中常见的智能指针`Box
`:将数据分配到堆上,拥有所有权,适合简单的堆分配场景。 `Rc
`:引用计数指针,允许多个所有者共享数据(单线程)。 `Arc
`:原子引用计数指针,适合多线程场景。 `RefCell
`:提供内部可变性,允许在不可变引用下修改数据。 `Mutex
` 和 `RwLock
`:用于多线程同步的智能指针。 自定义智能指针:可以根据需求实现特定逻辑。 3. 智能指针的关键 traitDeref 和 DerefMut:允许智能指针像普通引用一样解引用(* 操作符)。 Drop:定义智能指针在离开作用域时执行的清理逻辑。 其他 trait(如 Clone、Send、Sync)可能根据需求实现。 二、如何自定义一个智能指针自定义智能指针需要以下步骤:定义结构体:创建一个结构体来持有数据。 实现 Deref:使结构体能够像指针一样解引用。 实现 Drop(可选):定义析构时的行为。 添加其他功能:如引用计数、日志记录等。 确保安全性:遵循 Rust 的内存安全规则(如 Send 和 Sync)。 普通示例: ```rust use std::ops::{Deref, DerefMut}; use std::fmt::Debug; // 定义自定义智能指针 MyBox struct MyBox
{ value: T, // 存储实际数据 log: Vec
, // 记录操作日志 } // 为 MyBox 提供构造方法 impl
MyBox
{ fn new(value: T) -> MyBox
{ MyBox { value, log: Vec::new(), } } // 添加日志的辅助方法 fn logs(&mut self, message: &str) { self.log.push(message.to_string()); } // 获取日志 fn get_logs(&self) -> &Vec
{ &self.log } } // 实现 Deref trait,允许解引用 impl
Deref for MyBox
{ type Target = T; // 关联类型,指定解引用的目标类型 fn deref(&self) -> &Self::Target { // 在解引用时记录日志 // 注意:这里不能直接修改 self.log,因为 deref 是不可变借用 // 日志记录需要通过其他方式(如 RefCell 或 unsafe) &self.value } } // 实现 DerefMut trait,允许可变解引用 impl
DerefMut for MyBox
{ fn deref_mut(&mut self) -> &mut Self::Target { // 在可变解引用时记录日志 self.logs("DerefMut called"); &mut self.value } } // 实现 Drop trait,定义析构逻辑 impl
Drop for MyBox
{ fn drop(&mut self) { self.logs("Drop called"); println!("出作用域,释放内存, logs: {:?}", self.log); } } // 为调试方便实现 Debug trait impl
Debug for MyBox
{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("MyBox") .field("value", &self.value) .field("log", &self.log) .finish() } } // 主函数测试 fn main() { // 创建 MyBox 实例 let mut boxed = MyBox::new(String::from("Hello, 这是刚开始的内容!")); println!("初始内容: {:?}", boxed); // 解引用访问 println!("解引用获取内容: {}", *boxed); // 可变解引用修改值 这里要注意:之前初始数据是什么类型,那么修改的内容也要是同一类型 *boxed = String::from("Hello, 这是修改后的内容!"); println!("修改后的内容: {:?}", boxed); // 查看日志 println!("调用查看日志: {:?}", boxed.get_logs()); // boxed 离开作用域,自动调用 drop } ``` 如果需要复杂的内部状态管理(如在 deref 中修改 log),可通常通过 RefCell 或 Cell 实现: ```rust use std::ops::{Deref, DerefMut}; use std::fmt::Debug; use std::cell::RefCell; // 定义自定义智能指针 MyBox struct MyBox
{ value: T, // 存储实际数据 log: RefCell
>, // 使用 RefCell 管理日志以支持内部可变性 } // 为 MyBox 提供构造方法 impl
MyBox
{ fn new(value: T) -> MyBox
{ MyBox { value, log: RefCell::new(Vec::new()), // 初始化空的日志向量 } } // 获取日志(返回引用) fn get_logs(&self) -> std::cell::Ref
> { self.log.borrow() // 返回日志的不可变借用 } } // 实现 Deref trait,允许解引用 impl
Deref for MyBox
{ type Target = T; // 关联类型,指定解引用的目标类型 fn deref(&self) -> &Self::Target { // 使用 RefCell 的 borrow_mut 在不可变上下文中修改 log self.log.borrow_mut().push("Deref called".to_string()); &self.value } } // 实现 DerefMut trait,允许可变解引用 impl
DerefMut for MyBox
{ fn deref_mut(&mut self) -> &mut Self::Target { // 在可变上下文中修改 log self.log.borrow_mut().push("DerefMut called".to_string()); &mut self.value } } // 实现 Drop trait,定义析构逻辑 impl
Drop for MyBox
{ fn drop(&mut self) { self.log.borrow_mut().push("Drop called".to_string()); println!("出作用域,释放内存, logs: {:?}", self.log.borrow()); } } // 为调试方便实现 Debug trait impl
Debug for MyBox
{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("MyBox") .field("value", &self.value) .field("log", &self.log) .finish() } } // 主函数测试 fn main() { // 创建 MyBox 实例 let mut boxed = MyBox::new(String::from("Hello, 这是刚开始的内容!")); println!("初始内容: {:?}", boxed); // 解引用访问 println!("解引用获取内容: {}", *boxed); // 可变解引用修改值 这里要注意:之前初始数据是什么类型,那么修改的内容也要是同一类型 *boxed = String::from("Hello, 这是修改后的内容!"); println!("修改后的内容: {:?}", boxed); // 查看日志 println!("调用查看日志: {:?}", boxed.get_logs()); // boxed 离开作用域,自动调用 drop } ``` 支持多线程 ```rust use std::ops::{Deref, DerefMut}; use std::fmt::Debug; use std::sync::{Arc, Mutex}; // 定义自定义智能指针 MyBox struct MyBox
{ value: T, // 存储实际数据 log: Arc
>>, // 使用 Arc 和 Mutex 支持多线程 } // 为 MyBox 提供构造方法 impl
MyBox
{ fn new(value: T) -> MyBox
{ MyBox { value, log: Arc::new(Mutex::new(Vec::new())), } } // 获取日志(返回引用) fn get_logs(&self) -> std::sync::MutexGuard
> { self.log.lock().unwrap() } } // 实现 Deref trait,允许解引用 impl
Deref for MyBox
{ type Target = T; // 关联类型,指定解引用的目标类型 fn deref(&self) -> &Self::Target { // 使用 RefCell 的 borrow_mut 在不可变上下文中修改 log self.log.lock().unwrap().push("Deref called".to_string()); &self.value } } // 实现 DerefMut trait,允许可变解引用 impl
DerefMut for MyBox
{ fn deref_mut(&mut self) -> &mut Self::Target { // 在可变上下文中修改 log self.log.lock().unwrap().push("DerefMut called".to_string()); &mut self.value } } // 实现 Drop trait,定义析构逻辑 impl
Drop for MyBox
{ fn drop(&mut self) { self.log.lock().unwrap().push("Drop called".to_string()); println!("出作用域,释放内存, logs: {:?}", self.log.lock().unwrap()); } } // 为调试方便实现 Debug trait impl
Debug for MyBox
{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("MyBox") .field("value", &self.value) .field("log", &self.log) .finish() } } // 主函数测试 fn main() { // 创建 MyBox 实例 let mut boxed = MyBox::new(String::from("Hello, 这是刚开始的内容!")); println!("初始内容: {:?}", boxed); // 解引用访问 println!("解引用获取内容: {}", *boxed); // 可变解引用修改值 这里要注意:之前初始数据是什么类型,那么修改的内容也要是同一类型 *boxed = String::from("Hello, 这是修改后的内容!"); println!("修改后的内容: {:?}", boxed); // 查看日志 println!("调用查看日志: {:?}", boxed.get_logs()); // boxed 离开作用域,自动调用 drop } ```