Rust的所有权规则(ownership rule)允许在给定的范围内一次只存在一个所有者。但是,在某些情况下,需要与多个变量共享类型。例如,在GUI库中,每个子小部件(child widget)都需要有一个对其父容器小部件(parent container widget)的引用,以便根据来自用户发起的的调整大小事件(resize event)对子小部件进行布局。虽然生命周期允许开发者通过将父节点存储为&'a parent来从子节点引用父节点,但它通常受到值的生命周期参数a的限制。一旦范围结束,引用也就无效了。在这种情况下,我们需要更灵活的方法,这就涉及使用引用计数类型(reference counting types)。这些智能指针类型能够提供程序中值的共享所有权。
引用计数类型能够做到在细粒度级别上进行垃圾收集。在这种方法中,智能指针类型允许对封装的值有多个引用。在内部,智能指针保存它给出的引用数量的计数,并使用一个引用计数器(此处为refcount)活动,这里是一个整数值。当引用封装的智能指针值的变量超出作用域时,refcount值递减。一旦对该对象的所有引用都消失了,并且refcount达到0,就会释放该值。这就是引用计数指针通常的工作方式。
Rust为我们提供了两种参考计数指针类型:
我们会在这一章节里探索单线程情况,而后在第8章“并发性”中讨论下多线程的情况。
当我们与Rc类型交互时,它内部会发生以下变化:
使用引用计数容器为实现提供了更大的灵活性:我们可以像分发新副本一样分发值的副本,而不必精确跟踪引用何时超出了作用域。当然,这并不意味着我们可以以可变方式为内部值添加别名。
Rc
Rc内部保留两种引用: strong (Rc
如上面图表所见,我们有两个变量var1和var2,它们引用两个资源Obj1和Obj2。除此之外,Obj1也有一个对Obj2的引用Obj2也有一个对Obj1的引用。当var1和var2超出范围时,Obj1和Obj2的引用计数都为1。它们不会被释放,因为它们仍然相互关联。
可以使用弱引用(weak reference)来打破引用循环。另一个例子是,链表可以通过以下方式实现:通过对下一项和上一项的引用计数来维护链接。更好的方法是对一个方向使用强引用,对另一个方向使用弱引用。
让我们看看这是怎么做的。下面是一个可能最不实用但最适合学习数据结构的最小实现,即单链表:
// linked_list.rs
use std::rc::Rc;
#[derive(Debug)]
struct LinkedList {
head: Option>>
}
#[derive(Debug)]
struct Node {
next: Option>>,
data: T
}
impl LinkedList {
fn new() -> Self {
LinkedList { head: None }
}
fn append(&self, data: T) -> Self {
LinkedList {
head: Some(Rc::new(Node {
data: data,
next: self.head.clone()
}))
}
}
}
fn main() {
let list_of_nums = LinkedList::new().append(1).append(2);
println!("nums: {:?}", list_of_nums);
let list_of_strs = LinkedList::new().append("foo").append("bar");
println!("strs: {:?}", list_of_strs);
}
看一下,这个链表由两个结构体组成:LinkedList提供对列表第一个元素和列表的公共API的引用,Node包含实际的元素。请注意我们是如何使用Rc和在每个追加(append)上克隆下一个数据指针的。那么来看看在追加情况下发生了什么:
debug的输出println!证实了这一点:
不难看出,这体现出这个结构的一种函数式形式;每个append的工作方式都是在head(头部)添加数据,这意味着我们不必使用引用,而实际的列表引用可以保持不变。如果我们想保持这个简单的结构,但仍然有一个双链表,那么我们实际上必须改变现有的结构。
那么如何做相应的改变呢,姑且作为这一篇的作业,读者可以想一下,我们下篇再说。
https://doc.rust-lang.org/book
深入浅出 Rust,2018,范长春
Rust编程之道,2019, 张汉东
The Complete Rust Programming Reference Guide,2019, Rahul Sharma,Vesa Kaihlavirta,Claus Matzinger
Hands-On Data Structures and Algorithms with Rust,2018,Claus Matzinger
Beginning Rust ,2018,Carlo Milanesi
Rust Cookbook,2017,Vigneshwer Dhinakaran