• Rust8.1 Smart Pointers


    Rust学习笔记

    Rust编程语言入门教程课程笔记

    参考教材: The Rust Programming Language (by Steve Klabnik and Carol Nichols, with contributions from the Rust Community)

    Lecture 15: Smart Pointers

    src/main.rs

    use crate::List::{Cons, Nil};
    use std::ops::Deref;
    use crate::RcList::{RcCons, RcNil};
    use std::rc::Rc;
    use std::cell::RefCell;
    use crate::List2::{Cons2, Nil2};
    use crate::List3::{Cons3, Nil3};
    use std::rc::Weak;
    
    fn main() {
        //reference counting
        //Rc allows multiple ownership of immutable data
        //Example: String and Vec
        //Trait
        //Deref: allows an instance of a smart pointer to behave like a reference
        //Drop: allows you to customize the code that is run when an instance of the smart pointer goes out of scope
    
        //The most common smart pointers in the standard library
        //Box for allocating values on the heap
        //Rc, a reference counting type that enables multiple ownership
        //Ref and RefMut, accessed through RefCell, a type that enforces the borrowing rules at runtime instead of compile time
    
        //Box
        let b = Box::new(5);
        println!("b = {}", b);
    
        //Recursive Types
        let _list = Cons(1, 
            Box::new(Cons(2, 
                Box::new(Cons(3, 
                    Box::new(Nil))))));
    
        //Deref Trait
        //If a struct implements the Deref trait, we can use the * operator
        //to dereference an instance of that struct
        //Rust will analyze the types and use Deref::deref as many times as necessary
        //to get a reference to match the parameter's type
        let x = 5;
        let y = &x;
        let z = Box::new(x);
        let zz = MyBox::new(x);
    
        assert_eq!(5, x);
        assert_eq!(5, *y);
        assert_eq!(5, *z);
        assert_eq!(5, *zz);
    
        //Deref coercion
        //Rust does deref coercion when it finds types and trait implementations in three cases:
        //From &T to &U when T: Deref
        let m = MyBox::new(String::from("Rust"));
        hello(&m);//hello(&(*m)[..]);
        hello("Rust");
    
    
        //Drop Trait //in the prelude
        let c = CustomSmartPointer { data: String::from("my stuff") };
        drop(c);//force a value to be dropped sooner than the end of its scope
        let d = CustomSmartPointer { data: String::from("other stuff") };
        println!("CustomSmartPointers created.");
        //Output:
        //CustomSmartPointers created.
        //Dropping CustomSmartPointer with data `other stuff`!
        //Dropping CustomSmartPointer with data `my stuff`!
        
        //Rust automatically called drop for us when our instances went out of scope, 
        //calling the code we specified. 
        //Variables are dropped in the reverse order of their creation, so d was dropped before c.
    
        //Rc Reference Counted Smart Pointer
        //Rc enables multiple owners of the same data; Box and RefCell have single owners.
        //Rc keeps track of the number of references to a value which determines whether or not a value is still in use.
        //If there are zero references to a value, the value can be cleaned up without any references becoming invalid.
        //Rc is only for use in single-threaded scenarios.
    
        //Rc is only for use in single-threaded scenarios
    
        let list_a = Rc::new(RcCons(5, 
            Rc::new(RcCons(10, 
                Rc::new(RcNil)))));
        println!("count after creating list_a = {}", Rc::strong_count(&list_a));//1
    
        let list_b = RcCons(3, Rc::clone(&list_a));//Rc::clone doesn't make a deep copy of all the data like most types' implementations of clone do.
        println!("count after creating list_b = {}", Rc::strong_count(&list_a));//2
    
        {
            let list_c = RcCons(4, Rc::clone(&list_a));
            println!("count after creating list_c = {}", Rc::strong_count(&list_a));//3
        }
        
        println!("count after list_c goes out of scope = {}", Rc::strong_count(&list_a));//2
    
    
        //RefCell and the Interior Mutability Pattern
        //RefCell is useful when you’re sure your code follows the borrowing rules but the compiler is unable to understand and guarantee that.
        //RefCell can only be used in single-threaded scenarios.
    
    
        let value = Rc::new(RefCell::new(5));
        let a = Rc::new(Cons2(Rc::clone(&value), Rc::new(Nil2)));
        let b = Cons2(Rc::new(RefCell::new(6)), Rc::clone(&a));
        let c = Cons2(Rc::new(RefCell::new(10)), Rc::clone(&a));
    
        *value.borrow_mut() += 10;//borrow_mut returns a RefMut smart pointer
        println!("a after = {:?}", a);
        println!("b after = {:?}", b);
        println!("c after = {:?}", c);
    
        //Other Smart Pointers
        //Cell: a type that internally uses RefCell but also can be copied
        //Mutex: a type of smart pointer that locks access to the inner data using a mutex
    
        //Reference Cycles Can Leak Memory
        //Rc allows you to have multiple owners of some data, but it doesn’t let you mutate that data.
        //If we want to mutate data, we need to use the interior mutability pattern.
        //RefCell allows us to mutate contents inside an Rc.
        //RefCell keeps track of how many Ref and RefMut smart pointers are currently active.
        //When either kind of smart pointer is dropped, RefCell will decrease the count of the number of smart pointers that are active.
        //When the count of either goes back to zero, the RefCell will reclaim its inner value.
        
        let a = Rc::new(Cons3(5, RefCell::new(Rc::new(Nil3))));
        println!("a initial rc count = {}", Rc::strong_count(&a));//1
        println!("a next item = {:?}", a.tail());//Some(RefCell { value: Nil3 })
    
        let b = Rc::new(Cons3(10, RefCell::new(Rc::clone(&a))));
        println!("a rc count after b creation = {}", Rc::strong_count(&a));//2
        println!("b initial rc count = {}", Rc::strong_count(&b));//1
        println!("b next item = {:?}", b.tail());//Some(RefCell { value: Cons3(5, RefCell { value: Nil3 }) })
    
        if let Some(link) = a.tail() {
            *link.borrow_mut() = Rc::clone(&b);
        } 
    
        println!("b rc count after changing a = {}", Rc::strong_count(&b));//2
        println!("a rc count after changing a = {}", Rc::strong_count(&a));//2
    
        //println!("a next item = {:?}", a.tail());//Some(RefCell { value: Cons3(10, RefCell { value: Cons3(5, RefCell { value: Cons3(10, RefCell { value: Nil3 }) }) }) })
    
        //Weak References
        let leaf = Rc::new(Node {
            value: 3,
            parent: RefCell::new(Weak::new()),//Weak::new() creates a Weak that doesn’t have an owner
            children: RefCell::new(vec![]),
        });
    
        println!("leaf strong = {}, weak = {}", Rc::strong_count(&leaf), Rc::weak_count(&leaf));//1, 0
    
        println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());//None
        {
            let branch = Rc::new(Node {
                value: 5,
                parent: RefCell::new(Weak::new()),//Weak::new() creates a Weak that doesn’t have an owner
                children: RefCell::new(vec![Rc::clone(&leaf)]),
            });
    
            *leaf.parent.borrow_mut() = Rc::downgrade(&branch);//Rc::downgrade creates a Weak from a Rc reference
    
            println!("branch strong = {}, weak = {}", Rc::strong_count(&branch), Rc::weak_count(&branch));//1, 1
            println!("leaf strong = {}, weak = {}", Rc::strong_count(&leaf), Rc::weak_count(&leaf));//2, 0
        }
    
        println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());//Some(Node { value: 5, parent: RefCell { value: None }, children: RefCell { value: [Node { value: 3, parent: RefCell { value: None }, children: RefCell { value: [] } }] } })
    
        println!("leaf strong = {}, weak = {}", Rc::strong_count(&leaf), Rc::weak_count(&leaf));//1, 0
    }
    
    //Recursive Types
    enum List {
        Cons(i32, Box<List>),//Box is a pointer to another List. This has a known size.
        Nil,
    }
    
    //define a smart pointer
    struct MyBox<T>(T);
    
    //implement Deref trait for MyBox
    impl<T> MyBox<T> {
        fn new(x: T) -> MyBox<T> {
            MyBox(x)
        }
    }
    
    impl<T> Deref for MyBox<T> {//implement Deref trait for MyBox
        type Target = T;//associated type for the Deref trait to use
        fn deref(&self) -> &T {//return a reference to the value we want to access with the * operator
            &self.0
        }
    }
    
    fn hello(name: &str) {
        println!("Hello, {}!", name);
    }
    
    struct CustomSmartPointer {
        data: String,
    }
    
    impl Drop for CustomSmartPointer {//implement Drop trait
        fn drop(&mut self) {//drop method
            println!("Dropping CustomSmartPointer with data `{}`!", self.data);
        }
    }
    
    enum RcList {
        RcCons(i32, Rc<RcList>),
        RcNil,
    }
    
    pub trait Messenger {
        fn send(&self, msg: &str);
        
    }
    
    pub struct LimitTracker<'a, T: Messenger> {
        messenger: &'a T,
        value: usize,
        max: usize,
    }
    
    impl <'a, T> LimitTracker<'a, T> 
    where
        T: Messenger,
    {
        pub fn new(messenger: &T, max: usize) -> LimitTracker<T> {
            LimitTracker {
                messenger,//messenger: messenger,
                value: 0,
                max,
            }
        }
    
        pub fn set_value(&mut self, value: usize) {
            self.value = value;
            
            let percentage_of_max = self.value as f64 / self.max as f64;
            
            if percentage_of_max >= 1.0 {
                self.messenger.send("Error: You are over your quota!");
            } else if percentage_of_max >= 0.9 {
                self.messenger.send("Urgent warning: You've used up over 90% of your quota!");
            } else if percentage_of_max >= 0.75 {
                self.messenger.send("Warning: You've used up over 75% of your quota!");
            }
            
        }
    }
    
    #[derive(Debug)]
    enum List2 {
        Cons2(Rc<RefCell<i32>>, Rc<List2>),
        Nil2,
    }
    
    
    #[derive(Debug)]
    enum List3 {
        Cons3(i32, RefCell<Rc<List3>>),
        Nil3,
    }
    
    impl List3 {
        fn tail(&self) -> Option<&RefCell<Rc<List3>>> {
            match self {
                Cons3(_, item) => Some(item),
                Nil3 => None,
            }
        }
        
    }
    
    #[derive(Debug)]
    struct Node {
        value: i32,
        parent: RefCell<Weak<Node>>,
        children: RefCell<Vec<Rc<Node>>>,
        
    }
    
    
    #[cfg(test)]
    mod tests {
        use super::*;
    
        struct MockMessenger {
            sent_messages: RefCell<Vec<String>>,
        }
    
        impl MockMessenger {
            fn new() -> MockMessenger {
                MockMessenger { sent_messages: RefCell::new(vec![])}
            }
            
        }
    
        impl Messenger for MockMessenger {
            fn send(&self, message: &str) {
                self.sent_messages.borrow_mut().push(String::from(message));
                //borrow_mut returns a RefMut smart pointer
                //Every time we call borrow_mut, the mutable borrow counter goes up by one.
                //When a RefMut value goes out of scope, the mutable borrow counter goes down by one.
            }
            
        }
    
        #[test]
        fn it_sends_an_over_75_percent_warning_message() {
            let mock_messenger = MockMessenger::new();
            let mut limit_tracker = LimitTracker::new(&mock_messenger, 100);
            
            limit_tracker.set_value(80);
            
            assert_eq!(mock_messenger.sent_messages.borrow().len(), 1);
            //borrow returns a Ref smart pointer
            //Every time we call borrow, the immutable borrow counter goes up by one.
            //When a Ref value goes out of scope, the immutable borrow counter goes down by one.
        }
    }
    
    • 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
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
  • 相关阅读:
    基于PHP+MySQL仓库管理系统的设计与实现
    Golang 自定义函数库(个人笔记)
    Android开发——Fragment
    【教学类-34-10】20240313 春天拼图(Midjounery生成线描图,4*4格拼图块)(AI对话大师)
    SpringCloud Alibaba Sentinel实现熔断与限流
    Python3:PyArg_ParseTuple与Py_BuildValue
    A-Level经济例题解析及练习
    015-JAVA类与对象详细介绍
    视频质量度量VQM算法详细介绍
    【C语言程序设计】实验 3
  • 原文地址:https://blog.csdn.net/weixin_45347752/article/details/134484558