rust中智能指针的实现
作者:pumpkin84514
Rust智能指针通过所有权实现资源自动管理,包含Box、Rc、Arc、Mutex等类型,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
1、 什么是智能指针?Rust 三类指针对比
类型 | 安全性 | 借用检查 | 是否自动释放 | 功能特点 |
---|---|---|---|---|
&T, &mut T | ✅ 是 | ✅ 是 | ✅ 是 | 借用引用,不拥有数据 |
*const T, *mut T | ❌ 否 | ❌ 否 | ❌ 否 | 原生裸指针,用于 FFI、底层控制 |
智能指针(如 Box) | ✅ 是 | ✅ 是/部分 | ✅ 是 | 拥有数据,带有自动释放和额外功能 |
📌 智能指针本质是一个拥有值的结构体,实现了 Deref
和 Drop
,让你可以像指针一样访问值,又能自动释放资源。
2、原生指针 *const T:危险但有用
fn main() { let x = 5; let p: *const i32 = &x; // 获取原生指针 unsafe { println!("值是:{}", *p); // 只有在 unsafe 代码块中才能解引用 } }
✅ 只读,不会自动释放。
❌ 无生命周期、越界检查,容易悬垂。
💡 用于与 C 语言交互或实现底层结构。
手动释放:Box::into_raw / from_raw
fn main() { let b = Box::new(42); let ptr = Box::into_raw(b); // 转换为裸指针,不再自动释放 unsafe { let b2 = Box::from_raw(ptr); // 重新接管所有权 println!("恢复值:{}", b2); } // 自动释放 }
📌 记住:谁 into_raw,谁就必须 from_raw,否则泄漏!
3、常见智能指针逐个讲清
Box:在堆上分配值
fn main() { let b = Box::new(100); // 将整数 100 放到堆上 println!("b 的值是:{}", *b); // 解引用访问 } // 离开作用域自动释放(RAII)
适合:大对象、递归结构、强制所有权转移。
Rc:单线程引用计数共享
use std::rc::Rc; fn main() { let a = Rc::new("hello".to_string()); let b = Rc::clone(&a); // 引用计数 +1 println!("a = {}, b = {}", a, b); // 多个变量共享同一块内存 }
适合:多个地方共享不可变数据,如图结构、缓存。
📛 注意:不能用于多线程。
RefCell / Cell:内部可变性
use std::cell::RefCell; fn main() { let x = RefCell::new(10); // 创建可变容器 *x.borrow_mut() += 5; // 可变借用 println!("当前值: {}", x.borrow()); }
- RefCell:运行时借用检查,支持引用。
- Cell:适合
Copy
类型的值,用 get/set 读写。
Cow:写时复制,节省资源
use std::borrow::Cow; fn modify(input: Cow<str>) -> Cow<str> { if input.contains("x") { Cow::Owned(input.replace("x", "y")) // 真要改时才复制 } else { input } } fn main() { let s = Cow::Borrowed("hexo"); let result = modify(s); println!("结果:{}", result); }
适合:读取多、写入少的场景,如配置、模板处理。
Option 与智能指针
fn get_name() -> Option<&'static str> { Some("Tom") } fn main() { if let Some(name) = get_name() { println!("找到名字:{}", name); } }
Option 表示“可能有值”或“无值”,智能指针经常作为 Option 的值使用,用于“延迟初始化”。
4、 并发智能指针
Arc:线程安全引用计数
use std::sync::Arc; fn main() { let a = Arc::new(42); let b = Arc::clone(&a); println!("a = {}, b = {}", a, b); }
🧠 与 Rc 类似,但用原子操作实现,适合多线程。
Mutex:互斥锁保护数据
use std::sync::Mutex; fn main() { let m = Mutex::new(0); { let mut data = m.lock().unwrap(); *data += 1; } println!("当前值: {:?}", m); }
📌 一次只能一个线程修改。
RwLock:读多写少,效率高
use std::sync::RwLock; fn main() { let lock = RwLock::new(10); { let r1 = lock.read().unwrap(); let r2 = lock.read().unwrap(); println!("读者1: {}, 读者2: {}", r1, r2); } { let mut w = lock.write().unwrap(); *w += 10; } println!("写后值: {}", *lock.read().unwrap()); }
AtomicUsize:无锁计数器
use std::sync::atomic::{AtomicUsize, Ordering}; fn main() { let counter = AtomicUsize::new(0); counter.fetch_add(1, Ordering::SeqCst); // 原子 +1 println!("计数器值: {}", counter.load(Ordering::SeqCst)); }
适合:高性能并发状态计数,如连接数、任务状态。
5、高阶用法组合:Arc<Mutex>
use std::sync::{Arc, Mutex}; use std::thread; fn main() { let counter = Arc::new(Mutex::new(0)); let mut handles = vec![]; for _ in 0..10 { let c = Arc::clone(&counter); let handle = thread::spawn(move || { let mut num = c.lock().unwrap(); *num += 1; }); handles.push(handle); } for h in handles { h.join().unwrap(); } println!("最终结果: {}", *counter.lock().unwrap()); }
6、深入进阶:Weak / Pin / UnsafeCell
Weak:打破 Rc/Arc 的循环引用
use std::rc::{Rc, Weak}; use std::cell::RefCell; struct Node { next: RefCell<Option<Rc<Node>>>, prev: RefCell<Option<Weak<Node>>>, // 使用弱引用避免循环 }
📌 Rc::downgrade(&rc)
转换为 Weak,不计入引用计数
📌 .upgrade()
返回 Option<Rc>
Pin:防止对象被移动
use std::pin::Pin; fn main() { let data = String::from("hello"); let pinned = Pin::new(&data); println!("{}", pinned); }
📌 用于 Future、self-referential 结构
📌 Box::pin()
可固定对象
UnsafeCell:RefCell/Mutex 背后的魔法
use std::cell::UnsafeCell; struct MyType { data: UnsafeCell<i32>, } unsafe impl Sync for MyType {} fn main() { let x = MyType { data: UnsafeCell::new(0) }; unsafe { *x.data.get() = 42; println!("{}", *x.data.get()); } }
📌 允许穿透不可变引用进行修改,底层实现 RefCell、Mutex
场景速查表
类型 | 线程安全 | 可变性 | 常见用途 |
---|---|---|---|
Box | ❌ 否 | ✅ 是 | 所有权转移,递归结构 |
Rc | ❌ 否 | ❌ 否 | 单线程共享只读数据 |
RefCell | ❌ 否 | ✅ 是 | 内部可变性,运行时借用检查 |
Cell | ❌ 否 | ✅ 是 | Copy 类型小数据的替换 |
Cow | ✅ 是 | ✅ 是 | 写时复制,节省资源 |
Arc | ✅ 是 | ❌ 否 | 多线程只读共享 |
Mutex | ✅ 是 | ✅ 是 | 多线程可变共享 |
RwLock | ✅ 是 | ✅ 是 | 多读单写 |
AtomicUsize | ✅ 是 | ✅ 是 | 无锁计数器,高性能状态共享 |
Weak | ✅ 是 | ❌ 否 | 打破 Rc/Arc 循环引用 |
Pin | ✅ 是 | ❌ 否 | 防止移动,适用于异步/自引用结构 |
UnsafeCell | ❌(需手动保证) | ✅ 是 | RefCell / Mutex 的底层支撑 |
总结建议
- 智能指针 = 拥有数据 + 自动管理资源 + 像引用一样使用
- Rc、RefCell 是组合神器,但要小心引用环
- Arc + Mutex 是并发安全的常见搭配
- 遇到底层问题,了解 Pin / UnsafeCell 能更深入掌握 Rust 内存模型
到此这篇关于rust中智能指针的实现的文章就介绍到这了,更多相关rust 智能指针内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!