Appearance
Rust 智能指针
智能指针是 Rust 中具有额外功能的指针类型,它们不仅存储内存地址,还包含额外的元数据和功能。本章节将介绍 Rust 中的智能指针。
智能指针与引用的区别
- 引用:只是借用值,没有所有权
- 智能指针:拥有它们指向的数据
Box<T>
Box<T> 是最基本的智能指针,用于在堆上分配内存:
rust
fn main() {
// 在堆上分配一个 i32
let b = Box::new(5);
println!("b = {}", b);
}用途
- 当类型大小不确定时
- 当需要在编译时转移所有权时
- 当需要一个值的大小在编译时确定时
Rc<T>
Rc<T> 是引用计数智能指针,用于多个所有者共享数据:
rust
use std::rc::Rc;
fn main() {
let a = Rc::new(5);
let b = Rc::clone(&a);
let c = Rc::clone(&a);
println!("Reference count: {}", Rc::strong_count(&a));
println!("a = {}, b = {}, c = {}", a, b, c);
}用途
- 当需要多个所有者共享数据时
- 当数据的生命周期在编译时无法确定时
RefCell<T>
RefCell<T> 提供了内部可变性,允许在不可变引用的情况下修改数据:
rust
use std::cell::RefCell;
fn main() {
let value = RefCell::new(5);
// 获取可变引用并修改值
*value.borrow_mut() += 1;
// 获取不可变引用并读取值
println!("Value: {}", *value.borrow());
}用途
- 当需要在不可变引用的情况下修改数据时
- 当需要内部可变性时
Arc<T>
Arc<T> 是原子引用计数智能指针,用于多线程环境下的共享数据:
rust
use std::sync::Arc;
use std::thread;
fn main() {
let shared_data = Arc::new(5);
let mut handles = vec![];
for _ in 0..10 {
let data = Arc::clone(&shared_data);
let handle = thread::spawn(move || {
println!("Data: {}", data);
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
}用途
- 当需要在多线程环境下共享数据时
Mutex<T>
Mutex<T> 提供了互斥访问,确保在同一时间只有一个线程可以访问数据:
rust
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let shared_data = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let data = Arc::clone(&shared_data);
let handle = thread::spawn(move || {
let mut value = data.lock().unwrap();
*value += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Final value: {}", *shared_data.lock().unwrap());
}用途
- 当需要在多线程环境下安全地修改共享数据时
RwLock<T>
RwLock<T> 提供了读写锁,允许多个读操作同时进行,但写操作需要独占访问:
rust
use std::sync::{Arc, RwLock};
use std::thread;
fn main() {
let shared_data = Arc::new(RwLock::new(0));
// 读线程
let mut read_handles = vec![];
for _ in 0..5 {
let data = Arc::clone(&shared_data);
let handle = thread::spawn(move || {
let value = data.read().unwrap();
println!("Read value: {}", *value);
});
read_handles.push(handle);
}
// 写线程
let mut write_handles = vec![];
for i in 0..3 {
let data = Arc::clone(&shared_data);
let handle = thread::spawn(move || {
let mut value = data.write().unwrap();
*value = i;
println!("Write value: {}", *value);
});
write_handles.push(handle);
}
for handle in read_handles {
handle.join().unwrap();
}
for handle in write_handles {
handle.join().unwrap();
}
}用途
- 当读操作远多于写操作时
总结
- Box<T>:在堆上分配内存
- Rc<T>:引用计数,用于多个所有者共享数据
- RefCell<T>:内部可变性,允许在不可变引用的情况下修改数据
- Arc<T>:原子引用计数,用于多线程环境
- Mutex<T>:互斥锁,确保同一时间只有一个线程访问数据
- RwLock<T>:读写锁,允许多个读操作同时进行
智能指针是 Rust 中管理内存和并发的重要工具。通过本章节的学习,你应该已经掌握了 Rust 中常用的智能指针类型及其用途。