Rust学习笔记

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

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

Lecture 15: Smart Pointers

main.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
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
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<T> allows multiple ownership of immutable data
//Example: String and Vec<T>
//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<T> for allocating values on the heap
//Rc<T>, a reference counting type that enables multiple ownership
//Ref<T> and RefMut<T>, accessed through RefCell<T>, a type that enforces the borrowing rules at runtime instead of compile time

//Box<T>
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<Target=U>
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<T> Reference Counted Smart Pointer
//Rc<T> enables multiple owners of the same data; Box<T> and RefCell<T> have single owners.
//Rc<T> 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<T> is only for use in single-threaded scenarios.

//Rc<T> 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<T> and the Interior Mutability Pattern
//RefCell<T> is useful when you’re sure your code follows the borrowing rules but the compiler is unable to understand and guarantee that.
//RefCell<T> 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<T> smart pointer
println!("a after = {:?}", a);
println!("b after = {:?}", b);
println!("c after = {:?}", c);

//Other Smart Pointers
//Cell<T>: a type that internally uses RefCell<T> but also can be copied
//Mutex<T>: a type of smart pointer that locks access to the inner data using a mutex

//Reference Cycles Can Leak Memory
//Rc<T> 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<T> allows us to mutate contents inside an Rc<T>.
//RefCell<T> keeps track of how many Ref<T> and RefMut<T> smart pointers are currently active.
//When either kind of smart pointer is dropped, RefCell<T> will decrease the count of the number of smart pointers that are active.
//When the count of either goes back to zero, the RefCell<T> 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<T> 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<T> 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<T> from a Rc<T> 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<List> 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<T>
impl<T> MyBox<T> {
fn new(x: T) -> MyBox<T> {
MyBox(x)
}
}

impl<T> Deref for MyBox<T> {//implement Deref trait for MyBox<T>
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<T> smart pointer
//Every time we call borrow_mut, the mutable borrow counter goes up by one.
//When a RefMut<T> 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<T> smart pointer
//Every time we call borrow, the immutable borrow counter goes up by one.
//When a Ref<T> value goes out of scope, the immutable borrow counter goes down by one.
}
}