|
|
|
@ -89,7 +89,7 @@ fn main() {
|
|
|
|
|
|
|
|
|
|
这里在变量 `a` 中创建了一个 `Rc<List>` 实例来存放初值为 `5, Nil` 的 `List` 值。接着在变量 `b` 中创建了存放包含值 10 和指向列表 `a` 的 `List` 的另一个 `Rc<List>` 实例。
|
|
|
|
|
|
|
|
|
|
最后,修改 `a` 使其指向 `b` 而不是 `Nil`,这就创建了一个循环。为此需要使用 `tail` 方法获取 `a` 中 `RefCell<Rc<List>>` 的引用,并放入变量 `link` 中。接着使用 `RefCell<Rc<List>>` 的 `borrow_mut` 方法将其值从存放 `Nil` 的 `Rc` 修改为 `b` 中的 `Rc<List>`。
|
|
|
|
|
最后,修改 `a` 使其指向 `b` 而不是 `Nil`,这就创建了一个循环。为此需要使用 `tail` 方法获取 `a` 中 `RefCell<Rc<List>>` 的引用,并放入变量 `link` 中。接着使用 `RefCell<Rc<List>>` 的 `borrow_mut` 方法将其值从存放 `Nil` 的 `Rc<List>` 修改为 `b` 中的 `Rc<List>`。
|
|
|
|
|
|
|
|
|
|
如果保持最后的 `println!` 行注释并运行代码,会得到如下输出:
|
|
|
|
|
|
|
|
|
@ -103,7 +103,7 @@ b rc count after changing a = 2
|
|
|
|
|
a rc count after changing a = 2
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
可以看到将 `a` 修改为指向 `b` 之后,`a` 和 `b` 中都有的 `Rc<List>` 实例的引用计数为 2。在 `main` 的结尾,Rust 会尝试首先丢弃 `b`,这会使 `a` 和 `b` 中 `Rc` 实例的引用计数减 1。
|
|
|
|
|
可以看到将 `a` 修改为指向 `b` 之后,`a` 和 `b` 中都有的 `Rc<List>` 实例的引用计数为 2。在 `main` 的结尾,Rust 会尝试首先丢弃 `b`,这会使 `a` 和 `b` 中 `Rc<List>` 实例的引用计数减 1。
|
|
|
|
|
|
|
|
|
|
然而,因为 `a` 仍然引用 `b` 中的 `Rc<List>`,`Rc<List>` 的引用计数是 1 而不是 0,所以 `Rc<List>` 在堆上的内存不会被丢弃。其内存会因为引用计数为 1 而永远停留。为了更形象的展示,我们创建了一个如图 15-4 所示的引用循环:
|
|
|
|
|
|
|
|
|
@ -121,7 +121,7 @@ a rc count after changing a = 2
|
|
|
|
|
|
|
|
|
|
### 避免引用循环:将 `Rc<T>` 变为 `Weak<T>`
|
|
|
|
|
|
|
|
|
|
到目前为止,我们已经展示了调用 `Rc::clone` 会增加 `Rc<T>` 实例的 `strong_count`,和只在其 `strong_count` 为 0 时才会被清理的 `Rc<T>` 实例。你也可以通过调用 `Rc::downgrade` 并传递 `Rc` 实例的引用来创建其值的 **弱引用**(_weak reference_)。调用 `Rc::downgrade` 时会得到 `Weak<T>` 类型的智能指针。不同于将 `Rc<T>` 实例的 `strong_count` 加1,调用 `Rc::downgrade` 会将 `weak_count` 加1。`Rc<T>` 类型使用 `weak_count` 来记录其存在多少个 `Weak<T>` 引用,类似于 `strong_count`。其区别在于 `weak_count` 无需计数为 0 就能使 `Rc` 实例被清理。
|
|
|
|
|
到目前为止,我们已经展示了调用 `Rc::clone` 会增加 `Rc<T>` 实例的 `strong_count`,和只在其 `strong_count` 为 0 时才会被清理的 `Rc<T>` 实例。你也可以通过调用 `Rc::downgrade` 并传递 `Rc<T>` 实例的引用来创建其值的 **弱引用**(_weak reference_)。调用 `Rc::downgrade` 时会得到 `Weak<T>` 类型的智能指针。不同于将 `Rc<T>` 实例的 `strong_count` 加1,调用 `Rc::downgrade` 会将 `weak_count` 加1。`Rc<T>` 类型使用 `weak_count` 来记录其存在多少个 `Weak<T>` 引用,类似于 `strong_count`。其区别在于 `weak_count` 无需计数为 0 就能使 `Rc<T>` 实例被清理。
|
|
|
|
|
|
|
|
|
|
强引用代表如何共享 `Rc<T>` 实例的所有权,但弱引用并不属于所有权关系。他们不会造成引用循环,因为任何弱引用的循环会在其相关的强引用计数为 0 时被打断。
|
|
|
|
|
|
|
|
|
@ -247,7 +247,7 @@ fn main() {
|
|
|
|
|
leaf parent = None
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
当创建 `branch` 节点时,其也会新建一个 `Weak<Node>` 引用,因为 `branch` 并没有父节点。`leaf` 仍然作为 `branch` 的一个子节点。一旦在 `branch` 中有了 `Node` 实例,就可以修改 `leaf` 使其拥有指向父节点的 `Weak<Node>` 引用。这里使用了 `leaf` 中 `parent` 字段里的 `RefCell<Weak<Node>>` 的 `borrow_mut` 方法,接着使用了 `Rc::downgrade` 函数来从 `branch` 中的 `Rc` 值创建了一个指向 `branch` 的 `Weak<Node>` 引用。
|
|
|
|
|
当创建 `branch` 节点时,其也会新建一个 `Weak<Node>` 引用,因为 `branch` 并没有父节点。`leaf` 仍然作为 `branch` 的一个子节点。一旦在 `branch` 中有了 `Node` 实例,就可以修改 `leaf` 使其拥有指向父节点的 `Weak<Node>` 引用。这里使用了 `leaf` 中 `parent` 字段里的 `RefCell<Weak<Node>>` 的 `borrow_mut` 方法,接着使用了 `Rc::downgrade` 函数来从 `branch` 中的 `Rc<Node>` 值创建了一个指向 `branch` 的 `Weak<Node>` 引用。
|
|
|
|
|
|
|
|
|
|
当再次打印出 `leaf` 的父节点时,这一次将会得到存放了 `branch` 的 `Some` 值:现在 `leaf` 可以访问其父节点了!当打印出 `leaf` 时,我们也避免了如示例 15-26 中最终会导致栈溢出的循环:`Weak<Node>` 引用被打印为 `(Weak)`:
|
|
|
|
|
|
|
|
|
|