mirror of
https://github.com/gnu4cn/rust-lang-zh_CN.git
synced 2024-12-26 12:50:42 +08:00
Update Ch15
This commit is contained in:
parent
2939005482
commit
a8b28d757d
@ -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());
|
||||
|
||||
|
@ -1067,15 +1067,14 @@ Rust 的内存安全保证,使得意外创建出从未清理过的内存(称
|
||||
|
||||
*清单 15-26:创建出相互指向的两个 `List` 的循环引用*
|
||||
|
||||
我们创建一个 `Rc<List>` 实例,在变量 `a` 中持有一个 `List` 值,初始列表为 `5, Nil`。然后我们创建一个 `Rc<List>` 实例,在变量 `b` 中保存另一个 `List` 值,其中包含值 `10`,并指向 `a` 中的列表。
|
||||
|
||||
这里创建出了保存着变量 `a` 中,初始列表 `5, Nil` 的一个 `Rc<List>` 实例。随后这里又创建了保存着变量 `b` 中包含了值 `10` 并指向了 `a` 中清单的另一个 `Rc<List>` 实例。
|
||||
我们修改 `a` 使其指向 `b` 而不是 Nil,从而创建一个循环。为此,我们使用 `tail` 方法获取对 `a` 中 `RefCell<Rc<List>>` 的引用,我们将其放入变量 `link` 中。然后我们使用 `RefCell<Rc<List>>` 上的 `borrow_mut` 方法,将里面的值从一个持有 `Nil` 值的 `Rc<List>` 更改为 `b` 中的 `Rc<List>`。
|
||||
|
||||
这里修改了 `a` 从而其指向了 `b` 而非 `Nil`,于是创建了一个循环。咱们是通过是要那个 `tail` 方法,来获得到 `a` 中那个 `RefCell<Rc<List>>` 的引用,这里将其放入到了变量 `link` 中。随后这里使用了这个 `RefCell<Rc<List>>` 上的 `borrow_mut` 方法,来将保存着 `Nil` 的一个 `Rc<List>`,修改为保存到 `b` 中的那个 `Rc<List>`。
|
||||
|
||||
在保持那最后一个 `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<List>` 实例引用计数均为 `2`。在 `main` 的结尾,Rust 会弃用掉变量 `b`,这会将那个 `b` `Rc<List>` 实例的引用计数,从 `2` 降低到 `1`。因为他的引用计数为 `1` 而不是 `0`,因此那个 `Rc<List>` 在内存堆上的内存,在此刻就不会被弃用。随后 Rust 会弃用 `a`,这同样会将那个 `a` `Rc<List>` 实例的引用计数,从 `2` 降低到 `1`。由于另一 `Rc<List>` 实例仍指向着他,因此该实例的内存也无法被弃用。那么分配给该清单的内存,将永不会被收回。为形象表示这个引用循环,这里创建出了下图 15-4 中的图示。
|
||||
在咱们将 `a` 中的列表改为指向 `b` 后,`a` 和 `b` 中的 `Rc<List>` 实例的引用计数均为 `2`。在 `main` 的最后,Rust 弃用了变量 `b`,这使得 `b` 中的 `Rc<List>` 实例的引用计数从 `2` 减少到 `1`。`Rc<List>` 在内存堆中的内存此时不会被弃用,因为其引用计数为 `1` 而不是 `0`。然后 Rust 弃用 `a`,将 `a` 中的 `Rc<List>` 实例的引用计数从 `2` 减少到 `1`。由于另一 `Rc<List>` 实例仍指向他,因此该实例的内存也不能被弃用。分配给列表内存将永远保持未被收集的状态。为直观地表示这个引用循环,咱们创建了下图 15-4 中的图表。
|
||||
|
||||
![相互指向的列表 `a` 与 `b` 的一个循环引用](images/15-04.svg)
|
||||
|
||||
*图 15-04:相互指向的列表 `a` 与 `b` 的一个循环引用*
|
||||
*图 15-04:列表 `a` 和 `b` 相互指向的引用循环*
|
||||
|
||||
在取消注释掉其中最后一个 `println!` 而运行该程序时,Rust 就会尝试以 `a` 指向 `b` 指向 `a` 如此往复,打印出这个循环,直到他溢出内存栈为止。
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user