Rust 智能指针

智能指针

Rust 中的智能指针是一种数据结构,它不仅表现得像一个指针(通过实现 Deref trait),还拥有额外的元数据和功能(最典型的是所有权和生命周期管理)。它们通常使用结构体实现,并实现了 DerefDrop 这两个关键的 trait。

  • Deref: 通过实现 Deref,你可以使用 * 解引用运算符来访问其内部的数据和使用 & 来取得内部数据的引用。
  • Drop: 允许你在值离开作用域时执行自定义的清理代码

Deref

For example: &

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
use std::ops::Deref;

struct MyBox<T>(T);

impl<T> MyBox<T> {
    fn new(x: T) -> MyBox<T> {
        MyBox(x)
    }
}

impl<T> Deref for MyBox<T> {
    type Target = T;
    
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

fn hello(name: &str) {
    println!("Hello, {}!", name);
}

fn main() {
    let m = MyBox::new(String::from("Rust"));
    
    // 这里发生了 Deref Coercion!
    hello(&m);
    
    // 如果没有 Deref Coercion,你需要这样写:
    hello(&(*m)[..]);
    // 或者这样:
    hello(m.deref());
}

转换过程分析

当编译器看到 hello(&m) 时:

  1. m 的类型是 MyBox<String>
  2. &m 的类型是 &MyBox<String>
  3. hello 函数需要 &str
  4. 编译器发现 MyBox<T> 实现了 Deref<Target = T>
  5. 于是开始一系列自动转换:
    • &MyBox<String>&String (因为 MyBox<T>TargetT)
    • &String&str (因为 String 也实现了 Deref<Target = str>)

For example: *

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
use std::ops::Deref;

struct MyBox<T>(T);

impl<T> MyBox<T> {
    fn new(x: T) -> MyBox<T> {
        MyBox(x)
    }
}

// 关键:实现 Deref trait
impl<T> Deref for MyBox<T> {
    type Target = T;
    
    fn deref(&self) -> &Self::Target {
        &self.0  // 返回内部数据的引用
    }
}

fn main() {
    let x = 5;
    let y = MyBox::new(x);
    
    // 现在可以工作了!
    println!("{}", *y); // 输出: 5
    
    // 这相当于:
    println!("{}", *(y.deref())); // 显式调用 deref 方法
}

Drop

For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
struct CustomSmartPointer {
    data: String,
}

impl Drop for CustomSmartPointer {
    fn drop(&mut self) {
        println!("Dropping CustomSmartPointer with data `{}`!", self.data);
    }
}

fn main() {
    let c = CustomSmartPointer { data: String::from("my stuff") };
    let d = CustomSmartPointer { data: String::from("other stuff") };
    println!("CustomSmartPointers created.");
    // 这里会自动调用 c.drop() 和 d.drop()
}
// 输出:
// CustomSmartPointers created.
// Dropping CustomSmartPointer with data `other stuff`!
// Dropping CustomSmartPointer with data `my stuff`!

Rust 标准库常见的智能指针

Rust 标准库中最常见的智能指针包括:

  1. Box<T>: 在堆上分配数据;处理递归类型;trait 对象 (单一所有权)
  2. Rc<T>: 单线程下的多重只读所有权 (共享所有权)
  3. Arc<T>: 多线程下的多重只读所有权 (共享所有权)
  4. RefCell<T>: 单线程下的内部可变性 (单一所有权)
  5. Mutex<T>RwLock<T>: 多线程下的内部可变性和互斥访问 (单一所有权)

常见组合

  • Rc<RefCell<T>>:单线程下的共享可变数据。
  • Arc<Mutex<T>>Arc<RwLock<T>>:多线程下的共享可变数据。

对于所有权来说, Rc 和 Arc 对应 C++ 的 shared_ptr, 其他对应 unique_ptr。

0%