rust / intermediate
Snippet
Referenzkreise und Speicherlecks mit Rc<T>
Rc<T> bietet gemeinsames Eigentum durch Referenzzählung. Jedes Klone erhöht den Zähler, jeder Drop verringert ihn. Wenn der Zähler Null erreicht, wird der Wert freigegeben. Rc kann jedoch Referenzkreise nicht erkennen, was zu Speicherlecks führen kann. RefCell verzögert die Ausleihprüfung zur Laufzeit und ermöglicht mutable Referenzen durch gemeinsame Referenzen.
snippet.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
use std::rc::Rc;use std::cell::RefCell;struct Node {value: i32,children: RefCell<Vec<Rc<Node>>>,}impl Node {fn new(value: i32) -> Rc<Node> {Rc::new(Node {value,children: RefCell::new(vec![]),})}fn add_child(&self, child: Rc<Node>) {self.children.borrow_mut().push(child);}}fn main() {let root = Node::new(1);let leaf = Node::new(2);println!("Root strong count: {}", Rc::strong_count(&root));println!("Leaf strong count: {}", Rc::strong_count(&leaf));root.add_child(Rc::clone(&leaf));println!("After adding child:");println!("Root strong count: {}", Rc::strong_count(&root));println!("Leaf strong count: {}", Rc::strong_count(&leaf));let leaf_clone = Rc::clone(&leaf);drop(leaf);println!("After dropping original leaf:");println!("Leaf clone count: {}", Rc::strong_count(&leaf_clone));println!("Root has {} children", root.children.borrow().len());}
Erklärung
1
Rc::new(Node { ... })
Erstellt einen neuen referenzgezählten Node auf dem Heap
2
Rc::clone(&leaf)
Erstellt eine neue Referenz auf dieselbe Allokation, erhöht Zähler
3
Rc::strong_count(&root)
Gibt aktuellen Referenzzähler zurück, nützlich zum Debuggen von Leaks
4
RefCell<Vec<Rc<Node>>>
Innere Veränderlichkeit ermöglicht Mutation durch gemeinsame Referenz
5
root.add_child(Rc::clone(&leaf))
Kindreferenz erstellt gemeinsames Eigentum, beide halten einander am Leben