1
1
% References
2
2
3
+ This section gives a high-level view of the memory model that * all* Rust
4
+ programs must satisfy to be correct. Safe code is statically verified
5
+ to obey this model by the borrow checker. Unsafe code may go above
6
+ and beyond the borrow checker while still satisfying this model. The borrow
7
+ checker may also be extended to allow more programs to compile, as long as
8
+ this more fundamental model is satisfied.
9
+
3
10
There are two kinds of reference:
4
11
5
12
* Shared reference: ` & `
6
13
* Mutable reference: ` &mut `
7
14
8
15
Which obey the following rules:
9
16
10
- * A reference cannot outlive its referent A mutable reference cannot be aliased
17
+ * A reference cannot outlive its referent
18
+ * A mutable reference cannot be aliased
11
19
12
- To define aliasing, we must define the notion of * paths* and * liveness* .
20
+ That's it. That's the whole model. Of course, we should probably define
21
+ what * aliased* means. To define aliasing, we must define the notion of
22
+ * paths* and * liveness* .
13
23
14
24
15
25
16
26
17
27
# Paths
18
28
19
- If all Rust had were values, then every value would be uniquely owned by a
20
- variable or composite structure. From this we naturally derive a * tree * of
21
- ownership. The stack itself is the root of the tree, with every variable as its
22
- direct children. Each variable's direct children would be their fields (if any),
23
- and so on.
29
+ If all Rust had were values (no pointers) , then every value would be uniquely
30
+ owned by a variable or composite structure. From this we naturally derive a
31
+ * tree * of ownership. The stack itself is the root of the tree, with every
32
+ variable as its direct children. Each variable's direct children would be their
33
+ fields (if any), and so on.
24
34
25
35
From this view, every value in Rust has a unique * path* in the tree of
26
- ownership. References to a value can subsequently be interpreted as a path in
27
- this tree. Of particular interest are * ancestors* and * descendants* : if ` x ` owns
28
- ` y ` , then ` x ` is an * ancestor* of ` y ` , and ` y ` is a * descendant* of ` x ` . Note
36
+ ownership. Of particular interest are * ancestors* and * descendants* : if ` x ` owns
37
+ ` y ` , then ` x ` is an ancestor of ` y ` , and ` y ` is a descendant of ` x ` . Note
29
38
that this is an inclusive relationship: ` x ` is a descendant and ancestor of
30
39
itself.
31
40
41
+ We can then define references as simply * names* for paths. When you create a
42
+ reference, you're declaring that an ownership path exists to this address
43
+ of memory.
44
+
32
45
Tragically, plenty of data doesn't reside on the stack, and we must also
33
46
accommodate this. Globals and thread-locals are simple enough to model as
34
47
residing at the bottom of the stack (though we must be careful with mutable
35
48
globals). Data on the heap poses a different problem.
36
49
37
50
If all Rust had on the heap was data uniquely owned by a pointer on the stack,
38
- then we can just treat that pointer as a struct that owns the value on the heap.
39
- Box, Vec, String, and HashMap, are examples of types which uniquely own data on
40
- the heap.
51
+ then we could just treat such a pointer as a struct that owns the value on the
52
+ heap. Box, Vec, String, and HashMap, are examples of types which uniquely
53
+ own data on the heap.
41
54
42
55
Unfortunately, data on the heap is not * always* uniquely owned. Rc for instance
43
- introduces a notion of * shared* ownership. Shared ownership means there is no
44
- unique path. A value with no unique path limits what we can do with it. In
45
- general, only shared references can be created to these values. However
56
+ introduces a notion of * shared* ownership. Shared ownership of a value means
57
+ there is no unique path to it. A value with no unique path limits what we can do
58
+ with it.
59
+
60
+ In general, only shared references can be created to non-unique paths. However
46
61
mechanisms which ensure mutual exclusion may establish One True Owner
47
- temporarily, establishing a unique path to that value (and therefore all its
48
- children).
62
+ temporarily, establishing a unique path to that value (and therefore all
63
+ its children). If this is done, the value may be mutated. In particular, a
64
+ mutable reference can be taken.
49
65
50
66
The most common way to establish such a path is through * interior mutability* ,
51
67
in contrast to the * inherited mutability* that everything in Rust normally uses.
52
68
Cell, RefCell, Mutex, and RWLock are all examples of interior mutability types.
53
- These types provide exclusive access through runtime restrictions. However it is
54
- also possible to establish unique ownership without interior mutability. For
55
- instance, if an Rc has refcount 1, then it is safe to mutate or move its
56
- internals.
69
+ These types provide exclusive access through runtime restrictions.
70
+
71
+ An interesting case of this effect is Rc itself: if an Rc has refcount 1,
72
+ then it is safe to mutate or even move its internals. Note however that the
73
+ refcount itself uses interior mutability.
57
74
58
75
In order to correctly communicate to the type system that a variable or field of
59
76
a struct can have interior mutability, it must be wrapped in an UnsafeCell. This
@@ -62,6 +79,7 @@ that value. You still must yourself ensure that mutual exclusion is upheld.
62
79
63
80
64
81
82
+
65
83
# Liveness
66
84
67
85
Note: Liveness is not the same thing as a * lifetime* , which will be explained
0 commit comments