]> git.proxmox.com Git - rustc.git/blame - src/doc/book/src/ch15-05-interior-mutability.md
New upstream version 1.52.0~beta.3+dfsg1
[rustc.git] / src / doc / book / src / ch15-05-interior-mutability.md
CommitLineData
13cf67c4
XL
1## `RefCell<T>` and the Interior Mutability Pattern
2
13cf67c4
XL
3*Interior mutability* is a design pattern in Rust that allows you to mutate
4data even when there are immutable references to that data; normally, this
5action is disallowed by the borrowing rules. To mutate data, the pattern uses
6`unsafe` code inside a data structure to bend Rust’s usual rules that govern
e74abb32
XL
7mutation and borrowing. We haven’t yet covered unsafe code; we will in Chapter
819. We can use types that use the interior mutability pattern when we can
9ensure that the borrowing rules will be followed at runtime, even though the
10compiler can’t guarantee that. The `unsafe` code involved is then wrapped in a
11safe API, and the outer type is still immutable.
13cf67c4
XL
12
13Let’s explore this concept by looking at the `RefCell<T>` type that follows the
14interior mutability pattern.
15
16### Enforcing Borrowing Rules at Runtime with `RefCell<T>`
17
18Unlike `Rc<T>`, the `RefCell<T>` type represents single ownership over the data
19it holds. So, what makes `RefCell<T>` different from a type like `Box<T>`?
20Recall the borrowing rules you learned in Chapter 4:
21
22* At any given time, you can have *either* (but not both of) one mutable
23 reference or any number of immutable references.
24* References must always be valid.
25
26With references and `Box<T>`, the borrowing rules’ invariants are enforced at
27compile time. With `RefCell<T>`, these invariants are enforced *at runtime*.
28With references, if you break these rules, you’ll get a compiler error. With
29`RefCell<T>`, if you break these rules, your program will panic and exit.
30
31The advantages of checking the borrowing rules at compile time are that errors
32will be caught sooner in the development process, and there is no impact on
33runtime performance because all the analysis is completed beforehand. For those
34reasons, checking the borrowing rules at compile time is the best choice in the
35majority of cases, which is why this is Rust’s default.
36
37The advantage of checking the borrowing rules at runtime instead is that
38certain memory-safe scenarios are then allowed, whereas they are disallowed by
39the compile-time checks. Static analysis, like the Rust compiler, is inherently
40conservative. Some properties of code are impossible to detect by analyzing the
41code: the most famous example is the Halting Problem, which is beyond the scope
42of this book but is an interesting topic to research.
43
44Because some analysis is impossible, if the Rust compiler can’t be sure the
45code complies with the ownership rules, it might reject a correct program; in
46this way, it’s conservative. If Rust accepted an incorrect program, users
47wouldn’t be able to trust in the guarantees Rust makes. However, if Rust
48rejects a correct program, the programmer will be inconvenienced, but nothing
49catastrophic can occur. The `RefCell<T>` type is useful when you’re sure your
50code follows the borrowing rules but the compiler is unable to understand and
51guarantee that.
52
53Similar to `Rc<T>`, `RefCell<T>` is only for use in single-threaded scenarios
54and will give you a compile-time error if you try using it in a multithreaded
55context. We’ll talk about how to get the functionality of `RefCell<T>` in a
56multithreaded program in Chapter 16.
57
58Here is a recap of the reasons to choose `Box<T>`, `Rc<T>`, or `RefCell<T>`:
59
60* `Rc<T>` enables multiple owners of the same data; `Box<T>` and `RefCell<T>`
61 have single owners.
62* `Box<T>` allows immutable or mutable borrows checked at compile time; `Rc<T>`
63 allows only immutable borrows checked at compile time; `RefCell<T>` allows
64 immutable or mutable borrows checked at runtime.
65* Because `RefCell<T>` allows mutable borrows checked at runtime, you can
66 mutate the value inside the `RefCell<T>` even when the `RefCell<T>` is
67 immutable.
68
69Mutating the value inside an immutable value is the *interior mutability*
70pattern. Let’s look at a situation in which interior mutability is useful and
71examine how it’s possible.
72
73### Interior Mutability: A Mutable Borrow to an Immutable Value
74
75A consequence of the borrowing rules is that when you have an immutable value,
76you can’t borrow it mutably. For example, this code won’t compile:
77
78```rust,ignore,does_not_compile
74b04a01 79{{#rustdoc_include ../listings/ch15-smart-pointers/no-listing-01-cant-borrow-immutable-as-mutable/src/main.rs}}
13cf67c4
XL
80```
81
82If you tried to compile this code, you’d get the following error:
83
f035d41b 84```console
74b04a01 85{{#include ../listings/ch15-smart-pointers/no-listing-01-cant-borrow-immutable-as-mutable/output.txt}}
13cf67c4
XL
86```
87
88However, there are situations in which it would be useful for a value to mutate
89itself in its methods but appear immutable to other code. Code outside the
90value’s methods would not be able to mutate the value. Using `RefCell<T>` is
91one way to get the ability to have interior mutability. But `RefCell<T>`
92doesn’t get around the borrowing rules completely: the borrow checker in the
93compiler allows this interior mutability, and the borrowing rules are checked
94at runtime instead. If you violate the rules, you’ll get a `panic!` instead of
95a compiler error.
96
97Let’s work through a practical example where we can use `RefCell<T>` to mutate
98an immutable value and see why that is useful.
99
100#### A Use Case for Interior Mutability: Mock Objects
101
102A *test double* is the general programming concept for a type used in place of
103another type during testing. *Mock objects* are specific types of test doubles
104that record what happens during a test so you can assert that the correct
105actions took place.
106
107Rust doesn’t have objects in the same sense as other languages have objects,
108and Rust doesn’t have mock object functionality built into the standard library
109as some other languages do. However, you can definitely create a struct that
110will serve the same purposes as a mock object.
111
112Here’s the scenario we’ll test: we’ll create a library that tracks a value
113against a maximum value and sends messages based on how close to the maximum
114value the current value is. This library could be used to keep track of a
115user’s quota for the number of API calls they’re allowed to make, for example.
116
117Our library will only provide the functionality of tracking how close to the
118maximum a value is and what the messages should be at what times. Applications
119that use our library will be expected to provide the mechanism for sending the
120messages: the application could put a message in the application, send an
121email, send a text message, or something else. The library doesn’t need to know
122that detail. All it needs is something that implements a trait we’ll provide
123called `Messenger`. Listing 15-20 shows the library code:
124
125<span class="filename">Filename: src/lib.rs</span>
126
5869c6ff 127```rust,noplayground
74b04a01 128{{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-20/src/lib.rs}}
13cf67c4
XL
129```
130
131<span class="caption">Listing 15-20: A library to keep track of how close a
132value is to a maximum value and warn when the value is at certain levels</span>
133
134One important part of this code is that the `Messenger` trait has one method
135called `send` that takes an immutable reference to `self` and the text of the
6a06907d
XL
136message. This trait is the interface our mock object needs to implement so that
137the mock can be used in the same way a real object is. The other important part
138is that we want to test the behavior of the `set_value` method on the
139`LimitTracker`. We can change what we pass in for the `value` parameter, but
140`set_value` doesn’t return anything for us to make assertions on. We want to be
141able to say that if we create a `LimitTracker` with something that implements
142the `Messenger` trait and a particular value for `max`, when we pass different
143numbers for `value`, the messenger is told to send the appropriate messages.
13cf67c4
XL
144
145We need a mock object that, instead of sending an email or text message when we
146call `send`, will only keep track of the messages it’s told to send. We can
147create a new instance of the mock object, create a `LimitTracker` that uses the
148mock object, call the `set_value` method on `LimitTracker`, and then check that
149the mock object has the messages we expect. Listing 15-21 shows an attempt to
150implement a mock object to do just that, but the borrow checker won’t allow it:
151
152<span class="filename">Filename: src/lib.rs</span>
153
48663c56 154```rust,ignore,does_not_compile
74b04a01 155{{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-21/src/lib.rs:here}}
13cf67c4
XL
156```
157
158<span class="caption">Listing 15-21: An attempt to implement a `MockMessenger`
159that isn’t allowed by the borrow checker</span>
160
161This test code defines a `MockMessenger` struct that has a `sent_messages`
162field with a `Vec` of `String` values to keep track of the messages it’s told
163to send. We also define an associated function `new` to make it convenient to
164create new `MockMessenger` values that start with an empty list of messages. We
165then implement the `Messenger` trait for `MockMessenger` so we can give a
166`MockMessenger` to a `LimitTracker`. In the definition of the `send` method, we
167take the message passed in as a parameter and store it in the `MockMessenger`
168list of `sent_messages`.
169
170In the test, we’re testing what happens when the `LimitTracker` is told to set
171`value` to something that is more than 75 percent of the `max` value. First, we
172create a new `MockMessenger`, which will start with an empty list of messages.
173Then we create a new `LimitTracker` and give it a reference to the new
174`MockMessenger` and a `max` value of 100. We call the `set_value` method on the
175`LimitTracker` with a value of 80, which is more than 75 percent of 100. Then
176we assert that the list of messages that the `MockMessenger` is keeping track
177of should now have one message in it.
178
179However, there’s one problem with this test, as shown here:
180
6a06907d 181```console
74b04a01 182{{#include ../listings/ch15-smart-pointers/listing-15-21/output.txt}}
13cf67c4
XL
183```
184
185We can’t modify the `MockMessenger` to keep track of the messages, because the
186`send` method takes an immutable reference to `self`. We also can’t take the
187suggestion from the error text to use `&mut self` instead, because then the
188signature of `send` wouldn’t match the signature in the `Messenger` trait
189definition (feel free to try and see what error message you get).
190
191This is a situation in which interior mutability can help! We’ll store the
6a06907d 192`sent_messages` within a `RefCell<T>`, and then the `send` method will be
13cf67c4
XL
193able to modify `sent_messages` to store the messages we’ve seen. Listing 15-22
194shows what that looks like:
195
196<span class="filename">Filename: src/lib.rs</span>
197
fc512014 198```rust,noplayground
74b04a01 199{{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-22/src/lib.rs:here}}
13cf67c4
XL
200```
201
202<span class="caption">Listing 15-22: Using `RefCell<T>` to mutate an inner
203value while the outer value is considered immutable</span>
204
205The `sent_messages` field is now of type `RefCell<Vec<String>>` instead of
206`Vec<String>`. In the `new` function, we create a new `RefCell<Vec<String>>`
207instance around the empty vector.
208
209For the implementation of the `send` method, the first parameter is still an
210immutable borrow of `self`, which matches the trait definition. We call
211`borrow_mut` on the `RefCell<Vec<String>>` in `self.sent_messages` to get a
212mutable reference to the value inside the `RefCell<Vec<String>>`, which is
213the vector. Then we can call `push` on the mutable reference to the vector to
214keep track of the messages sent during the test.
215
216The last change we have to make is in the assertion: to see how many items are
217in the inner vector, we call `borrow` on the `RefCell<Vec<String>>` to get an
218immutable reference to the vector.
219
220Now that you’ve seen how to use `RefCell<T>`, let’s dig into how it works!
221
222#### Keeping Track of Borrows at Runtime with `RefCell<T>`
223
224When creating immutable and mutable references, we use the `&` and `&mut`
225syntax, respectively. With `RefCell<T>`, we use the `borrow` and `borrow_mut`
226methods, which are part of the safe API that belongs to `RefCell<T>`. The
227`borrow` method returns the smart pointer type `Ref<T>`, and `borrow_mut`
228returns the smart pointer type `RefMut<T>`. Both types implement `Deref`, so we
229can treat them like regular references.
230
231The `RefCell<T>` keeps track of how many `Ref<T>` and `RefMut<T>` smart
232pointers are currently active. Every time we call `borrow`, the `RefCell<T>`
233increases its count of how many immutable borrows are active. When a `Ref<T>`
234value goes out of scope, the count of immutable borrows goes down by one. Just
235like the compile-time borrowing rules, `RefCell<T>` lets us have many immutable
236borrows or one mutable borrow at any point in time.
237
238If we try to violate these rules, rather than getting a compiler error as we
239would with references, the implementation of `RefCell<T>` will panic at
240runtime. Listing 15-23 shows a modification of the implementation of `send` in
241Listing 15-22. We’re deliberately trying to create two mutable borrows active
242for the same scope to illustrate that `RefCell<T>` prevents us from doing this
243at runtime.
244
245<span class="filename">Filename: src/lib.rs</span>
246
247```rust,ignore,panics
74b04a01 248{{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-23/src/lib.rs:here}}
13cf67c4
XL
249```
250
251<span class="caption">Listing 15-23: Creating two mutable references in the
252same scope to see that `RefCell<T>` will panic</span>
253
254We create a variable `one_borrow` for the `RefMut<T>` smart pointer returned
255from `borrow_mut`. Then we create another mutable borrow in the same way in the
256variable `two_borrow`. This makes two mutable references in the same scope,
257which isn’t allowed. When we run the tests for our library, the code in Listing
25815-23 will compile without any errors, but the test will fail:
259
f035d41b 260```console
74b04a01 261{{#include ../listings/ch15-smart-pointers/listing-15-23/output.txt}}
13cf67c4
XL
262```
263
264Notice that the code panicked with the message `already borrowed:
265BorrowMutError`. This is how `RefCell<T>` handles violations of the borrowing
266rules at runtime.
267
268Catching borrowing errors at runtime rather than compile time means that you
269would find a mistake in your code later in the development process and possibly
270not until your code was deployed to production. Also, your code would incur a
271small runtime performance penalty as a result of keeping track of the borrows
272at runtime rather than compile time. However, using `RefCell<T>` makes it
273possible to write a mock object that can modify itself to keep track of the
274messages it has seen while you’re using it in a context where only immutable
275values are allowed. You can use `RefCell<T>` despite its trade-offs to get more
276functionality than regular references provide.
277
278### Having Multiple Owners of Mutable Data by Combining `Rc<T>` and `RefCell<T>`
279
280A common way to use `RefCell<T>` is in combination with `Rc<T>`. Recall that
281`Rc<T>` lets you have multiple owners of some data, but it only gives immutable
282access to that data. If you have an `Rc<T>` that holds a `RefCell<T>`, you can
283get a value that can have multiple owners *and* that you can mutate!
284
285For example, recall the cons list example in Listing 15-18 where we used
286`Rc<T>` to allow multiple lists to share ownership of another list. Because
287`Rc<T>` holds only immutable values, we can’t change any of the values in the
288list once we’ve created them. Let’s add in `RefCell<T>` to gain the ability to
289change the values in the lists. Listing 15-24 shows that by using a
290`RefCell<T>` in the `Cons` definition, we can modify the value stored in all
291the lists:
292
293<span class="filename">Filename: src/main.rs</span>
294
295```rust
74b04a01 296{{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-24/src/main.rs}}
13cf67c4
XL
297```
298
299<span class="caption">Listing 15-24: Using `Rc<RefCell<i32>>` to create a
300`List` that we can mutate</span>
301
302We create a value that is an instance of `Rc<RefCell<i32>>` and store it in a
303variable named `value` so we can access it directly later. Then we create a
304`List` in `a` with a `Cons` variant that holds `value`. We need to clone
305`value` so both `a` and `value` have ownership of the inner `5` value rather
306than transferring ownership from `value` to `a` or having `a` borrow from
307`value`.
308
309We wrap the list `a` in an `Rc<T>` so when we create lists `b` and `c`, they
310can both refer to `a`, which is what we did in Listing 15-18.
311
312After we’ve created the lists in `a`, `b`, and `c`, we add 10 to the value in
313`value`. We do this by calling `borrow_mut` on `value`, which uses the
314automatic dereferencing feature we discussed in Chapter 5 (see the section
9fa01778
XL
315[“Where’s the `->` Operator?”][wheres-the---operator]<!-- ignore -->) to
316dereference the `Rc<T>` to the inner `RefCell<T>` value. The `borrow_mut`
317method returns a `RefMut<T>` smart pointer, and we use the dereference operator
318on it and change the inner value.
13cf67c4
XL
319
320When we print `a`, `b`, and `c`, we can see that they all have the modified
321value of 15 rather than 5:
322
f035d41b 323```console
74b04a01 324{{#include ../listings/ch15-smart-pointers/listing-15-24/output.txt}}
13cf67c4
XL
325```
326
327This technique is pretty neat! By using `RefCell<T>`, we have an outwardly
328immutable `List` value. But we can use the methods on `RefCell<T>` that provide
329access to its interior mutability so we can modify our data when we need to.
330The runtime checks of the borrowing rules protect us from data races, and it’s
331sometimes worth trading a bit of speed for this flexibility in our data
332structures.
333
334The standard library has other types that provide interior mutability, such as
335`Cell<T>`, which is similar except that instead of giving references to the
336inner value, the value is copied in and out of the `Cell<T>`. There’s also
337`Mutex<T>`, which offers interior mutability that’s safe to use across threads;
338we’ll discuss its use in Chapter 16. Check out the standard library docs for
339more details on the differences between these types.
9fa01778
XL
340
341[wheres-the---operator]: ch05-03-method-syntax.html#wheres-the---operator