Appearance
智能指针
允许在堆上分配数据,同时在栈上管理引用计数。超出作用域时,自动释放内存。
注意:智能指针的引用计数必须在单线程环境下使用,否则会导致数据不一致。
适用的场景:
- 编译时未知大小的类型,但又需要确切大小的上下文中使用类型值的时候
- 有大量数据,并希望在确保数据不被拷贝的情况下转移所有权的时候
- 希望拥有一个值,只关心它的类型是否实现了特定trait而不是具体类型的时候
Box/RC/Arc/Mutex
Box<T> - 堆上分配数据
rust
fn main() {
let a = Box::new(5);
println!("{}", a);
}一个比较复杂的示例:
rust
enum MyList {
Cons(i32, Box<MyList>),
Nil,
}
fn main() {
let list = MyList::Cons(1, Box::new(MyList::Cons(2, Box::new(MyList::Nil))));
}其中,Cons表示链表节点,Nil表示链表结束。ConList的每一项包含两个元素,一个是当前项,一个是下一项。
Rc<T> - 单线程引用计数
带引用计数的智能指针。
rust
use std::rc::Rc;
fn main() {
let a = Rc::new(5);
let b = Rc::clone(&a);
println!("{} {}", a, b);
}注意:Rc只能用于单线程,跨线程使用需用Arc。
Arc<T> - 多线程原子引用计数
rust
use std::sync::Arc;
use std::thread;
fn main() {
let a = Arc::new(5);
let a_clone = Arc::clone(&a);
let handle = thread::spawn(move || {
println!("{}", a_clone);
});
handle.join().unwrap();
}注意:Arc是线程安全的,但内部数据不可变。若需修改,需配合Mutex。
Mutex<T> - 互斥锁
rust
use std::sync::Mutex;
use std::thread;
fn main() {
let m = Mutex::new(5);
{
let mut num = m.lock().unwrap();
*num = 10;
}
println!("{:?}", m);
}Arc + Mutex 多线程共享可变数据
rust
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let data = Arc::new(Mutex::new(0));
let data_clone = Arc::clone(&data);
let handle = thread::spawn(move || {
let mut d = data_clone.lock().unwrap();
*d += 1;
});
handle.join().unwrap();
println!("{}", data.lock().unwrap());
}注意事项:
- Arc实现了Clone,但clone只是增加引用计数
- Mutex的lock会阻塞当前线程,获取后记得释放(RAII自动释放)
- 尽量缩小锁的范围,避免性能问题