ch15-00-smart-pointers.md
commit 1fedfc4b96c2017f64ecfcf41a0a07e2e815f24f
指针(pointer)是一个包含内存地址的变量的通用概念。这个地址引用,或 ” 指向”(points at)一些其
他数据。Rust 中最常见的指针是第四章介绍的 引用(reference)。引用以 & 符号为标志并借用了他们所
指向的值。除了引用数据没有任何其他特殊功能。它们也没有任何额外开销,所以应用得最多。
另一方面,智能指针(smart pointers)是一类数据结构,他们的表现类似指针,但是也拥有额外的元数
据和功能。智能指针的概念并不为 Rust 所独有;其起源于 C++ 并存在于其他语言中。Rust 标准库中不
同的智能指针提供了多于引用的额外功能。本章将会探索的一个例子便是 引用计数(reference counting)
智能指针类型,其允许数据有多个所有者。引用计数智能指针记录总共有多少个所有者,并当没有任何
所有者时负责清理数据。
在 Rust 中,普通引用和智能指针的一个额外的区别是引用是一类只借用数据的指针;相反,在大部分情
况下,智能指针 拥有他们指向的数据。
实际上本书中已经出现过一些智能指针,比如第八章的 String 和 Vec,虽然当时我们并不这么称呼
它们。这些类型都属于智能指针因为它们拥有一些数据并允许你修改它们。它们也带有元数据(比如他
们的容量)和额外的功能或保证(String 的数据总是有效的 UTF-8 编码)。
智能指针通常使用结构体实现。智能指针区别于常规结构体的显著特性在于其实现了 Deref 和 Drop
trait。Deref trait 允许智能指针结构体实例表现的像引用一样,这样就可以编写既用于引用、又用于智
能指针的代码。Drop trait 允许我们自定义当智能指针离开作用域时运行的代码。本章会讨论这些 trait
以及为什么对于智能指针来说他们很重要。
考虑到智能指针是一个在 Rust 经常被使用的通用设计模式,本章并不会覆盖所有现存的智能指针。很多
库都有自己的智能指针而你也可以编写属于你自己的智能指针。这里将会讲到的是来自标准库中最常用
的一些:
• Box,用于在堆上分配值
• Rc,一个引用计数类型,其数据可以有多个所有者
• Ref 和 RefMut,通过 RefCell 访问。(RefCell 是一个在运行时而不是在编译时执行
借用规则的类型)。
另外我们会涉及 内部可变性(interior mutability)模式,这是不可变类型暴露出改变其内部值的 API。
我们也会讨论 引用循环(reference cycles)会如何泄漏内存,以及如何避免。
让我们开始吧!
使用 Box 指向堆上的数据
ch15-01-box.md commit 359895c6b2e440275a663ee1a3c17e6a94fdc62b
最简单直接的智能指针是 box,其类型是 Box。box 允许你将一个值放在堆上而不是栈上。留在栈上
的则是指向堆数据的指针。如果你想回顾一下栈与堆的区别请参考第四章。
除了数据被储存在堆上而不是栈上之外,box 没有性能损失。不过也没有很多额外的功能。它们多用于
如下场景:
• 当有一个在编译时未知大小的类型,而又想要在需要确切大小的上下文中使用这个类型值的时候
• 当有大量数据并希望在确保数据不被拷贝的情况下转移所有权的时候
• 当希望拥有一个值并只关心它的类型是否实现了特定 trait 而不是其具体类型的时候
我们会在 ”box 允许创建递归类型” 部分展示第一种场景。在第二种情况中,转移大量数据的所有权可能
会花费很长的时间,因为数据在栈上进行了拷贝。为了改善这种情况下的性能,可以通过 box 将这些数
据储存在堆上。接着,只有少量的指针数据在栈上被拷贝。第三种情况被称为 trait 对象(trait object),
第十七章刚好有一整个部分 ”box 允许创建递归类型” 专门讲解这个主题。所以这里所学的内容会在第十
七章再次用上!