diff --git a/src/ch15-04-rc.md b/src/ch15-04-rc.md index 223cc60..8585529 100644 --- a/src/ch15-04-rc.md +++ b/src/ch15-04-rc.md @@ -65,7 +65,7 @@ error[E0382]: use of moved value: `a` 可以改变 `Cons` 的定义来存放一个引用,不过接着必须指定生命周期参数。通过指定生命周期参数,表明列表中的每一个元素都至少与列表本身存在的一样久。例如,借用检查器不会允许 `let a = Cons(10, &Nil);` 编译,因为临时值 `Nil` 会在 `a` 获取其引用之前就被丢弃了。 -相反,我们修改 `List` 的定义为使用 `Rc` 代替 `Box`,如列表 15-18 所示。现在每一个 `Cons` 变量都包含一个值和一个指向 `List` 的 `Rc`。当创建 `b` 时,不同于获取 `a` 的所有权,这里会克隆 `a` 所包含的 `Rc`,这会将引用计数从 1 增加到 2 并允许 `a` 和 `b` 共享 `Rc` 中数据的所有权。创建 `c` 时也会克隆 `a`,这会将引用计数从 2 增加为 3。每次调用 `Rc::clone`,`Rc` 中数据的引用计数都会增加,直到有零个引用之前其数据都不会被清理。 +相反,我们修改 `List` 的定义为使用 `Rc` 代替 `Box`,如列表 15-18 所示。现在每一个 `Cons` 变量都包含一个值和一个指向 `List` 的 `Rc`。当创建 `b` 时,不同于获取 `a` 的所有权,这里会克隆 `a` 所包含的 `Rc`,这会将引用计数从 1 增加到 2 并允许 `a` 和 `b` 共享 `Rcc` 中数据的所有权。创建 `c` 时也会克隆 `a`,这会将引用计数从 2 增加为 3。每次调用 `Rc::clone`,`Rc` 中数据的引用计数都会增加,直到有零个引用之前其数据都不会被清理。 文件名: src/main.rs @@ -136,7 +136,7 @@ count after c goes out of scope = 2 我们能够看到 `a` 中 `Rc` 的初始引用计数为1,接着每次调用 `clone`,计数会增加1。当 `c` 离开作用域时,计数减1。不必像调用 `Rc::clone` 增加引用计数那样调用一个函数来减少计数;`Drop` trait 的实现当 `Rc` 值离开作用域时自动减少引用计数。 -从这个例子我们所不能看到的是,在 `main` 的结尾当 `b` 然后是 `a` 离开作用域时,此处计数会是 0,同时 `Rc` 被完全清理。使用 `Rc` 允许一个值有多个所有者,引用计数则确保只要任何所有者依然存在其值也保持有效。 +从这个例子我们所不能看到的是,在 `main` 的结尾当 `b` 然后是 `a` 离开作用域时,此处计数会是 0,同时 `Rc` 被完全清理。使用 `Rc` 允许一个值有多个所有者,引用计数则确保只要任何所有者依然存在其值也保持有效。 通过不可变引用, `Rc` 允许在程序的多个部分之间只读地共享数据。如果 `Rc` 也允许多个可变引用,则会违反第四章讨论的借用规则之一:相同位置的多个可变借用可能造成数据竞争和不一致。不过可以修改数据是非常有用的!在下一部分,我们将讨论内部可变性模式和 `RefCell` 类型,它可以与 `Rc` 结合使用来处理不可变性的限制。 diff --git a/src/ch15-06-reference-cycles.md b/src/ch15-06-reference-cycles.md index d52a503..dcbabb6 100644 --- a/src/ch15-06-reference-cycles.md +++ b/src/ch15-06-reference-cycles.md @@ -89,7 +89,7 @@ fn main() { 这里在变量 `a` 中创建了一个 `Rc` 实例来存放初值为 `5, Nil` 的 `List` 值。接着在变量 `b` 中创建了存放包含值 10 和指向列表 `a` 的 `List` 的另一个 `Rc` 实例。 -最后,修改 `a` 使其指向 `b` 而不是 `Nil`,这就创建了一个循环。为此需要使用 `tail` 方法获取 `a` 中 `RefCell>` 的引用,并放入变量 `link` 中。接着使用 `RefCell>` 的 `borrow_mut` 方法将其值从存放 `Nil` 的 `Rc` 修改为 `b` 中的 `Rc`。 +最后,修改 `a` 使其指向 `b` 而不是 `Nil`,这就创建了一个循环。为此需要使用 `tail` 方法获取 `a` 中 `RefCell>` 的引用,并放入变量 `link` 中。接着使用 `RefCell>` 的 `borrow_mut` 方法将其值从存放 `Nil` 的 `Rc` 修改为 `b` 中的 `Rc`。 如果保持最后的 `println!` 行注释并运行代码,会得到如下输出: @@ -103,7 +103,7 @@ b rc count after changing a = 2 a rc count after changing a = 2 ``` -可以看到将 `a` 修改为指向 `b` 之后,`a` 和 `b` 中都有的 `Rc` 实例的引用计数为 2。在 `main` 的结尾,Rust 会尝试首先丢弃 `b`,这会使 `a` 和 `b` 中 `Rc` 实例的引用计数减 1。 +可以看到将 `a` 修改为指向 `b` 之后,`a` 和 `b` 中都有的 `Rc` 实例的引用计数为 2。在 `main` 的结尾,Rust 会尝试首先丢弃 `b`,这会使 `a` 和 `b` 中 `Rc` 实例的引用计数减 1。 然而,因为 `a` 仍然引用 `b` 中的 `Rc`,`Rc` 的引用计数是 1 而不是 0,所以 `Rc` 在堆上的内存不会被丢弃。其内存会因为引用计数为 1 而永远停留。为了更形象的展示,我们创建了一个如图 15-4 所示的引用循环: @@ -121,7 +121,7 @@ a rc count after changing a = 2 ### 避免引用循环:将 `Rc` 变为 `Weak` -到目前为止,我们已经展示了调用 `Rc::clone` 会增加 `Rc` 实例的 `strong_count`,和只在其 `strong_count` 为 0 时才会被清理的 `Rc` 实例。你也可以通过调用 `Rc::downgrade` 并传递 `Rc` 实例的引用来创建其值的 **弱引用**(_weak reference_)。调用 `Rc::downgrade` 时会得到 `Weak` 类型的智能指针。不同于将 `Rc` 实例的 `strong_count` 加1,调用 `Rc::downgrade` 会将 `weak_count` 加1。`Rc` 类型使用 `weak_count` 来记录其存在多少个 `Weak` 引用,类似于 `strong_count`。其区别在于 `weak_count` 无需计数为 0 就能使 `Rc` 实例被清理。 +到目前为止,我们已经展示了调用 `Rc::clone` 会增加 `Rc` 实例的 `strong_count`,和只在其 `strong_count` 为 0 时才会被清理的 `Rc` 实例。你也可以通过调用 `Rc::downgrade` 并传递 `Rc` 实例的引用来创建其值的 **弱引用**(_weak reference_)。调用 `Rc::downgrade` 时会得到 `Weak` 类型的智能指针。不同于将 `Rc` 实例的 `strong_count` 加1,调用 `Rc::downgrade` 会将 `weak_count` 加1。`Rc` 类型使用 `weak_count` 来记录其存在多少个 `Weak` 引用,类似于 `strong_count`。其区别在于 `weak_count` 无需计数为 0 就能使 `Rc` 实例被清理。 强引用代表如何共享 `Rc` 实例的所有权,但弱引用并不属于所有权关系。他们不会造成引用循环,因为任何弱引用的循环会在其相关的强引用计数为 0 时被打断。 @@ -247,7 +247,7 @@ fn main() { leaf parent = None ``` -当创建 `branch` 节点时,其也会新建一个 `Weak` 引用,因为 `branch` 并没有父节点。`leaf` 仍然作为 `branch` 的一个子节点。一旦在 `branch` 中有了 `Node` 实例,就可以修改 `leaf` 使其拥有指向父节点的 `Weak` 引用。这里使用了 `leaf` 中 `parent` 字段里的 `RefCell>` 的 `borrow_mut` 方法,接着使用了 `Rc::downgrade` 函数来从 `branch` 中的 `Rc` 值创建了一个指向 `branch` 的 `Weak` 引用。 +当创建 `branch` 节点时,其也会新建一个 `Weak` 引用,因为 `branch` 并没有父节点。`leaf` 仍然作为 `branch` 的一个子节点。一旦在 `branch` 中有了 `Node` 实例,就可以修改 `leaf` 使其拥有指向父节点的 `Weak` 引用。这里使用了 `leaf` 中 `parent` 字段里的 `RefCell>` 的 `borrow_mut` 方法,接着使用了 `Rc::downgrade` 函数来从 `branch` 中的 `Rc` 值创建了一个指向 `branch` 的 `Weak` 引用。 当再次打印出 `leaf` 的父节点时,这一次将会得到存放了 `branch` 的 `Some` 值:现在 `leaf` 可以访问其父节点了!当打印出 `leaf` 时,我们也避免了如示例 15-26 中最终会导致栈溢出的循环:`Weak` 引用被打印为 `(Weak)`: