study_example/smart_pointer/
refcell_pointer.rs

1use std::borrow::BorrowMut;
2use std::cell::RefCell;
3use std::rc::Rc;
4pub trait Messager {
5    fn send(&self, msg: &str);
6}
7
8pub struct LimitTracker<'a, T: Messager> {
9    messager: &'a T,
10    value: usize,
11    max: usize,
12}
13
14impl<'a, T> LimitTracker<'a, T>
15where
16    T: Messager,
17{
18    pub fn new(messager: &'a T, max: usize) -> LimitTracker<'a, T> {
19        LimitTracker {
20            messager,
21            value: 0,
22            max,
23        }
24    }
25
26    pub fn set_value(&mut self, value: usize) {
27        self.value = value;
28        let percentage_of_max = self.value as f64 / self.max as f64;
29        if percentage_of_max >= 1.0 {
30            self.messager.send("Error: You are over your quota!");
31        } else if percentage_of_max >= 0.9 {
32            self.messager
33                .send("Urgent warning: You've used up over 90% of your quota!");
34        } else if percentage_of_max >= 0.75 {
35            self.messager
36                .send("Warning: You've used up over 75% of your quota!");
37        }
38    }
39}
40
41struct MockMessager {
42    sent_message: std::cell::RefCell<Vec<String>>,
43}
44
45impl MockMessager {
46    fn new() -> MockMessager {
47        MockMessager {
48            sent_message: std::cell::RefCell::new(vec![]),
49        }
50    }
51}
52
53impl Messager for MockMessager {
54    fn send(&self, msg: &str) {
55        // error[E0596]: cannot borrow `self.sent_message` as mutable, as it is behind a `&` reference
56        // 解法:采用refcell类型的指针
57        self.sent_message.borrow_mut().push(String::from(msg));
58        self.sent_message.borrow_mut().push(String::from(msg));
59        let mut borrow1 = self.sent_message.borrow_mut();
60        // 运行时错误: thread 'main' panicked at 'already borrowed: BorrowMutError', study-example/src/smart_pointer/refcell_pointer.rs:57:45
61        // let mut borrow2 = self.sent_message.borrow_mut();
62        borrow1.push(String::from(msg));
63        // borrow2.push(String::from(msg));
64    }
65}
66
67#[derive(Debug)]
68enum List {
69    Cons(Rc<RefCell<i32>>, Rc<List>),
70    Nil,
71}
72/// 组合Rc<T>和RcCell<T>
73fn cons_modify_usage() {
74    let value = Rc::new(RefCell::new(5));
75    let a = Rc::new(List::Cons(Rc::clone(&value), Rc::new(List::Nil)));
76    let b = List::Cons(Rc::new(RefCell::new(3)), Rc::clone(&a));
77    let c = List::Cons(Rc::new(RefCell::new(4)), Rc::clone(&a));
78    let mut value_borrow = (*value).borrow_mut();
79    *value_borrow += 100;
80    println!("value: {:?}", value);
81    println!("a after = {:?}", a);
82    println!("b after = {:?}", b);
83    println!("c after = {:?}", c);
84}
85/// 调用结果如下
86/// ```txt
87/// mock message len: 3
88/// a after = Cons(RefCell { value: <borrowed> }, Nil)
89/// b after = Cons(RefCell { value: 3 }, Cons(RefCell { value: <borrowed> }, Nil))
90/// c after = Cons(RefCell { value: 4 }, Cons(RefCell { value: <borrowed> }, Nil))
91/// ```
92pub fn refcell_pointer_study() {
93    let mock_messager = MockMessager::new();
94    let mut limit_tracker = LimitTracker::new(&mock_messager, 100);
95    limit_tracker.set_value(80);
96    println!(
97        "mock message len: {}",
98        mock_messager.sent_message.borrow().len()
99    );
100    cons_modify_usage();
101}