初面网初面网

智能指针

允许在堆上分配数据,同时在栈上管理引用计数。超出作用域时,自动释放内存。

注意:智能指针的引用计数必须在单线程环境下使用,否则会导致数据不一致。

适用的场景:

  • 编译时未知大小的类型,但又需要确切大小的上下文中使用类型值的时候
  • 有大量数据,并希望在确保数据不被拷贝的情况下转移所有权的时候
  • 希望拥有一个值,只关心它的类型是否实现了特定trait而不是具体类型的时候

Box/RC/Arc/Mutex

Box<T> - 堆上分配数据

fn main() {
  let a = Box::new(5);
  println!("{}", a);
}

一个比较复杂的示例:

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> - 单线程引用计数

带引用计数的智能指针。

use std::rc::Rc;

fn main() {
  let a = Rc::new(5);
  let b = Rc::clone(&a);
  println!("{} {}", a, b);
}

注意:Rc只能用于单线程,跨线程使用需用Arc。

Arc<T> - 多线程原子引用计数

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> - 互斥锁

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 多线程共享可变数据

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自动释放)
  • 尽量缩小锁的范围,避免性能问题

更新于 2026/6/11