diff --git a/projects/ref_cycle_demo/src/main.rs b/projects/ref_cycle_demo/src/main.rs index 6fe1657..37e3c7f 100644 --- a/projects/ref_cycle_demo/src/main.rs +++ b/projects/ref_cycle_demo/src/main.rs @@ -18,14 +18,24 @@ impl List { } fn main() { - let a = Rc::new(Cons(5, RefCell::new(Rc::new(Nil)))); + let a = Rc::new( + Cons( + 5, + RefCell::new(Rc::new(Nil)) + ) + ); println! ("a 的初始 rc 计数 = {}", Rc::strong_count(&a)); println! ("a 的下一条目 = {:?}", a.tail()); - let b = Rc::new(Cons(10, RefCell::new(Rc::clone(&a)))); + let b = Rc::new( + Cons( + 10, + RefCell::new(Rc::clone(&a)) + ) + ); - println! ("b 的创建后 a 的 rc 计数 = {}", Rc::strong_count(&a)); + println! ("创建 b 后 a 的 rc 计数 = {}", Rc::strong_count(&a)); println! ("b 的初始 rc 计数 = {}", Rc::strong_count(&b)); println! ("b 的下一条目 = {:?}", b.tail()); diff --git a/src/Ch15_Smart_Pointers.md b/src/Ch15_Smart_Pointers.md index 7ded1eb..4594a2e 100644 --- a/src/Ch15_Smart_Pointers.md +++ b/src/Ch15_Smart_Pointers.md @@ -1067,15 +1067,14 @@ Rust 的内存安全保证,使得意外创建出从未清理过的内存(称 *清单 15-26:创建出相互指向的两个 `List` 的循环引用* +我们创建一个 `Rc` 实例,在变量 `a` 中持有一个 `List` 值,初始列表为 `5, Nil`。然后我们创建一个 `Rc` 实例,在变量 `b` 中保存另一个 `List` 值,其中包含值 `10`,并指向 `a` 中的列表。 -这里创建出了保存着变量 `a` 中,初始列表 `5, Nil` 的一个 `Rc` 实例。随后这里又创建了保存着变量 `b` 中包含了值 `10` 并指向了 `a` 中清单的另一个 `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!` 被注释掉,而运行此代码时,就会得到下面的输出: +咱们暂时保持最后的 `println!` 注释掉,而运行此代码时,咱们将得到下面的输出: ```console -$ cargo run lennyp@vm-manjaro +$ cargo run Compiling ref_cycle_demo v0.1.0 (/home/lennyp/rust-lang/ref_cycle_demo) Finished dev [unoptimized + debuginfo] target(s) in 1.20s Running `target/debug/ref_cycle_demo` @@ -1088,11 +1087,11 @@ b 的下一条目 = Some(RefCell { value: Cons(5, RefCell { value: Nil }) }) 在修改 a 之后 a 的 rc 计数 = 2 ``` -在将 `a` 中的列表修改为指向 `b` 后,与 `b` 中的两个 `Rc` 实例引用计数均为 `2`。在 `main` 的结尾,Rust 会弃用掉变量 `b`,这会将那个 `b` `Rc` 实例的引用计数,从 `2` 降低到 `1`。因为他的引用计数为 `1` 而不是 `0`,因此那个 `Rc` 在内存堆上的内存,在此刻就不会被弃用。随后 Rust 会弃用 `a`,这同样会将那个 `a` `Rc` 实例的引用计数,从 `2` 降低到 `1`。由于另一 `Rc` 实例仍指向着他,因此该实例的内存也无法被弃用。那么分配给该清单的内存,将永不会被收回。为形象表示这个引用循环,这里创建出了下图 15-4 中的图示。 +在咱们将 `a` 中的列表改为指向 `b` 后,`a` 和 `b` 中的 `Rc` 实例的引用计数均为 `2`。在 `main` 的最后,Rust 弃用了变量 `b`,这使得 `b` 中的 `Rc` 实例的引用计数从 `2` 减少到 `1`。`Rc` 在内存堆中的内存此时不会被弃用,因为其引用计数为 `1` 而不是 `0`。然后 Rust 弃用 `a`,将 `a` 中的 `Rc` 实例的引用计数从 `2` 减少到 `1`。由于另一 `Rc` 实例仍指向他,因此该实例的内存也不能被弃用。分配给列表内存将永远保持未被收集的状态。为直观地表示这个引用循环,咱们创建了下图 15-4 中的图表。 ![相互指向的列表 `a` 与 `b` 的一个循环引用](images/15-04.svg) -*图 15-04:相互指向的列表 `a` 与 `b` 的一个循环引用* +*图 15-04:列表 `a` 和 `b` 相互指向的引用循环* 在取消注释掉其中最后一个 `println!` 而运行该程序时,Rust 就会尝试以 `a` 指向 `b` 指向 `a` 如此往复,打印出这个循环,直到他溢出内存栈为止。