Skip to content

Commit f164080

Browse files
committed
Use Weak Rc (non-owning reference) to break the reference cycle.
1 parent 1970aa9 commit f164080

File tree

2 files changed

+123
-0
lines changed

2 files changed

+123
-0
lines changed

c15_6_ref_cycles/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "c15_6_ref_cycles"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]

c15_6_ref_cycles/src/main.rs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
use crate::List::{Cons, Nil};
2+
use std::cell::RefCell;
3+
use std::rc::{Rc, Weak};
4+
5+
#[derive(Debug)]
6+
enum List {
7+
Cons(i32, RefCell<Rc<List>>),
8+
Nil,
9+
}
10+
11+
impl List {
12+
fn tail(&self) -> Option<&RefCell<Rc<List>>> {
13+
match self {
14+
Cons(_, item) => Some(item),
15+
Nil => None,
16+
}
17+
}
18+
}
19+
20+
21+
22+
#[derive(Debug)]
23+
struct Node {
24+
value: i32,
25+
parent: RefCell<Weak<Node>>,
26+
children: RefCell<Vec<Rc<Node>>>,
27+
}
28+
29+
30+
fn main() {
31+
let a = Rc::new(Cons(5, RefCell::new(Rc::new(Nil))));
32+
33+
println!("a initial rc count = {}", Rc::strong_count(&a));
34+
println!("a next item = {:?}", a.tail());
35+
36+
let b = Rc::new(Cons(10, RefCell::new(Rc::clone(&a))));
37+
38+
println!("a rc count after b creation = {}", Rc::strong_count(&a));
39+
println!("b initial rc count = {}", Rc::strong_count(&b));
40+
println!("next item of b = {:?}", b.tail());
41+
42+
if let Some(link) = a.tail() {
43+
*link.borrow_mut() = Rc::clone(&b);
44+
}
45+
println!("a tail is now changed to be b.");
46+
47+
println!("b rc count after changing a = {}", Rc::strong_count(&b));
48+
println!("a rc count after changing a = {}", Rc::strong_count(&a));
49+
50+
// Uncomment the next line to see that we have a cycle;
51+
// it will overflow the stack
52+
//println!("a next item = {:?}", a.tail());
53+
/*
54+
RefCell { value: Cons(10, RefCell {
55+
...
56+
thread 'main' has overflowed its stack
57+
fatal runtime error: stack overflow
58+
Aborted (core dumped)
59+
*/
60+
61+
let leaf = Rc::new(Node {
62+
value: 3,
63+
parent: RefCell::new(Weak::new()),
64+
children: RefCell::new(vec![]),
65+
});
66+
67+
println!("leaf parent = {:?}, value={}", leaf.parent.borrow().upgrade(),
68+
leaf.value);
69+
70+
println!(
71+
"leaf strong = {}, weak = {}",
72+
Rc::strong_count(&leaf),
73+
Rc::weak_count(&leaf),
74+
);
75+
76+
{
77+
let branch = Rc::new(Node {
78+
value: 5,
79+
parent: RefCell::new(Weak::new()),
80+
children: RefCell::new(vec![Rc::clone(&leaf)]),
81+
});
82+
println!(
83+
"branch strong = {}, weak = {}, value={}",
84+
Rc::strong_count(&branch),
85+
Rc::weak_count(&branch),
86+
branch.value,
87+
);
88+
89+
*leaf.parent.borrow_mut() = Rc::downgrade(&branch);
90+
println!("parent of leaf is changed to branch.");
91+
92+
println!(
93+
"branch strong = {}, weak = {}",
94+
Rc::strong_count(&branch),
95+
Rc::weak_count(&branch),
96+
);
97+
98+
println!(
99+
"leaf strong = {}, weak = {}",
100+
Rc::strong_count(&leaf),
101+
Rc::weak_count(&leaf),
102+
);
103+
println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
104+
}
105+
println!("branch is out of scope.");
106+
println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
107+
println!(
108+
"leaf strong = {}, weak = {}",
109+
Rc::strong_count(&leaf),
110+
Rc::weak_count(&leaf),
111+
);
112+
113+
println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
114+
115+
}

0 commit comments

Comments
 (0)