]> git.proxmox.com Git - rustc.git/blob - src/doc/book/second-edition/src/ch15-02-deref.md
914cfa99d3b8b9d5b4275037ccedcd2d3066b29e
[rustc.git] / src / doc / book / second-edition / src / ch15-02-deref.md
1 ## Treating Smart Pointers like Regular References with the `Deref` Trait
2
3 Implementing `Deref` trait allows us to customize the behavior of the
4 *dereference operator* `*`(as opposed to the multiplication or glob operator).
5 By implementing `Deref` in such a way that a smart pointer can be treated like
6 a regular reference, we can write code that operates on references and use that
7 code with smart pointers too.
8
9 <!-- Why would we want to override the dereference operator? Can you lay that
10 out? -->
11 <!-- Attempted above. /Carol -->
12
13 <!-- I'd suggest introducing what you mean by "convenient" here, if we are
14 using it as the reason we want to use Deref -->
15 <!-- I've removed convenient from the first paragraph and foreshadowed in a
16 different way in the below paragraph /Carol -->
17
18 Let’s first take a look at how `*` works with regular references, then try and
19 define our own type like `Box<T>` and see why `*` doesn’t work like a
20 reference. We’ll explore how implementing the `Deref` trait makes it possible
21 for smart pointers to work in a similar way as references. Finally, we’ll look
22 at the *deref coercion* feature of Rust and how that lets us work with either
23 references or smart pointers.
24
25 ### Following the Pointer to the Value with `*`
26
27 <!-- I want to avoid too much cross referencing, I think it can be distracting,
28 make the reader feel they need to flip back but they don't really, here -->
29 <!-- Ok, guess we went too far then! I've been adding *more* cross referencing
30 so that the reader can go back if they've forgotten something we've already
31 covered. /Carol -->
32
33 <!--Oh! I see, de-reference, meaning we cut the tie between the data and the
34 reference? I've assumed so above, please correct if not! -->
35 <!-- I wouldn't describe it as "cutting the tie"; the tie is still there. It's
36 more like we're following an arrow (the pointer) to find the value. Let us know
37 if this explanation is still unclear. /Carol -->
38
39 A regular reference is a type of pointer, and one way to think of a pointer is
40 that it’s an arrow to a value stored somewhere else. In Listing 15-8, let’s
41 create a reference to an `i32` value then use the dereference operator to
42 follow the reference to the data:
43
44 <!-- We'll start with an example of dereferencing and re-allocating references
45 to `i32` values: -->
46 <!-- Is this what this is an example of? -->
47 <!-- No, there isn't any re-allocation happening here; allocation is a term
48 that means asking for more space in order to hold data (as we covered in
49 chapter 4). What were you trying to convey with "re-allocating", exactly? Have
50 we addressed whatever was confusing here before? /Carol -->
51
52 <!-- We've reworked the following sections in this chapter heavily because the
53 `Mp3` example seemed to be confusing with the metadata that was involved.
54 Interested to see if this breakdown works better or not. /Carol -->
55
56 <span class="filename">Filename: src/main.rs</span>
57
58 ```rust
59 fn main() {
60 let x = 5;
61 let y = &x;
62
63 assert_eq!(5, x);
64 assert_eq!(5, *y);
65 }
66 ```
67
68 <span class="caption">Listing 15-8: Using the dereference operator to follow a
69 reference to an `i32` value</span>
70
71 The variable `x` holds an `i32` value, `5`. We set `y` equal to a reference to
72 `x`. We can assert that `x` is equal to `5`. However, if we want to make an
73 assertion about the value in `y`, we have to use `*y` to follow the reference
74 to the value that the reference is pointing to (hence *de-reference*). Once we
75 de-reference `y`, we have access to the integer value `y` is pointing to that
76 we can compare with `5`.
77
78 If we try to write `assert_eq!(5, y);` instead, we’ll get this compilation
79 error:
80
81 ```text
82 error[E0277]: the trait bound `{integer}: std::cmp::PartialEq<&{integer}>` is
83 not satisfied
84 --> src/main.rs:6:5
85 |
86 6 | assert_eq!(5, y);
87 | ^^^^^^^^^^^^^^^^^ can't compare `{integer}` with `&{integer}`
88 |
89 = help: the trait `std::cmp::PartialEq<&{integer}>` is not implemented for
90 `{integer}`
91 ```
92
93 Comparing a reference to a number with a number isn’t allowed because they’re
94 different types. We have to use `*` to follow the reference to the value it’s
95 pointing to.
96
97 ### Using `Box<T>` Like a Reference
98
99 We can rewrite the code in Listing 15-8 to use a `Box<T>` instead of a
100 reference, and the de-reference operator will work the same way as shown in
101 Listing 15-9:
102
103 <span class="filename">Filename: src/main.rs</span>
104
105 ```rust
106 fn main() {
107 let x = 5;
108 let y = Box::new(x);
109
110 assert_eq!(5, x);
111 assert_eq!(5, *y);
112 }
113 ```
114
115 <span class="caption">Listing 15-9: Using the dereference operator on a
116 `Box<i32>`</span>
117
118 The only part of Listing 15-8 that we changed was to set `y` to be an instance
119 of a box pointing to the value in `x` rather than a reference pointing to the
120 value of `x`. In the last assertion, we can use the dereference operator to
121 follow the box’s pointer in the same way that we did when `y` was a reference.
122 Let’s explore what is special about `Box<T>` that enables us to do this by
123 defining our own box type.
124
125 ### Defining Our Own Smart Pointer
126
127 Let’s build a smart pointer similar to the `Box<T>` type that the standard
128 library has provided for us, in order to experience that smart pointers don’t
129 behave like references by default. Then we’ll learn about how to add the
130 ability to use the dereference operator.
131
132 `Box<T>` is ultimately defined as a tuple struct with one element, so Listing
133 15-10 defines a `MyBox<T>` type in the same way. We’ll also define a `new`
134 function to match the `new` function defined on `Box<T>`:
135
136 <span class="filename">Filename: src/main.rs</span>
137
138 ```rust
139 struct MyBox<T>(T);
140
141 impl<T> MyBox<T> {
142 fn new(x: T) -> MyBox<T> {
143 MyBox(x)
144 }
145 }
146 ```
147
148 <span class="caption">Listing 15-10: Defining a `MyBox<T>` type</span>
149
150 We define a struct named `MyBox` and declare a generic parameter `T`, since we
151 want our type to be able to hold values of any type. `MyBox` is a tuple struct
152 with one element of type `T`. The `MyBox::new` function takes one parameter of
153 type `T` and returns a `MyBox` instance that holds the value passed in.
154
155 Let’s try adding the code from Listing 15-9 to the code in Listing 15-10 and
156 changing `main` to use the `MyBox<T>` type we’ve defined instead of `Box<T>`.
157 The code in Listing 15-11 won’t compile because Rust doesn’t know how to
158 dereference `MyBox`:
159
160 <span class="filename">Filename: src/main.rs</span>
161
162 ```rust,ignore
163 fn main() {
164 let x = 5;
165 let y = MyBox::new(x);
166
167 assert_eq!(5, x);
168 assert_eq!(5, *y);
169 }
170 ```
171
172 <span class="caption">Listing 15-11: Attempting to use `MyBox<T>` in the same
173 way we were able to use references and `Box<T>`</span>
174
175 The compilation error we get is:
176
177 ```text
178 error: type `MyBox<{integer}>` cannot be dereferenced
179 --> src/main.rs:14:19
180 |
181 14 | assert_eq!(5, *y);
182 | ^^
183 ```
184
185 Our `MyBox<T>` type can’t be dereferenced because we haven’t implemented that
186 ability on our type. To enable dereferencing with the `*` operator, we can
187 implement the `Deref` trait.
188
189 ### Implementing the `Deref` Trait Defines How To Treat a Type Like a Reference
190
191 As we discussed in Chapter 10, in order to implement a trait, we need to
192 provide implementations for the trait’s required methods. The `Deref` trait,
193 provided by the standard library, requires implementing one method named
194 `deref` that borrows `self` and returns a reference to the inner data. Listing
195 15-12 contains an implementation of `Deref` to add to the definition of `MyBox`:
196
197 <span class="filename">Filename: src/main.rs</span>
198
199 ```rust
200 use std::ops::Deref;
201
202 # struct MyBox<T>(T);
203 impl<T> Deref for MyBox<T> {
204 type Target = T;
205
206 fn deref(&self) -> &T {
207 &self.0
208 }
209 }
210 ```
211
212 <span class="caption">Listing 15-12: Implementing `Deref` on `MyBox<T>`</span>
213
214 The `type Target = T;` syntax defines an associated type for this trait to use.
215 Associated types are a slightly different way of declaring a generic parameter
216 that you don’t need to worry about too much for now; we’ll cover it in more
217 detail in Chapter 19.
218
219 <!-- Is it possible to just use a method for declaring a generic parameter we
220 have seen before, so we can focus on the deref trait here? -->
221 <!-- No, this is how the `Deref` trait is defined in the standard library, so
222 this is what you have to specify in order to implement it. /Carol -->
223
224 We filled in the body of the `deref` method with `&self.0` so that `deref`
225 returns a reference to the value we want to access with the `*` operator. The
226 `main` function from Listing 15-11 that calls `*` on the `MyBox<T>` value now
227 compiles and the assertions pass!
228
229 Without the `Deref` trait, the compiler can only dereference `&` references.
230 The `Deref` trait’s `deref` method gives the compiler the ability to take a
231 value of any type that implements `Deref` and call the `deref` method in order
232 to get a `&` reference that it knows how to dereference.
233
234 When we typed `*y` in Listing 15-11, what Rust actually ran behind the scenes
235 was this code:
236
237 ```rust,ignore
238 *(y.deref())
239 ```
240
241 <!-- why is that happening behind the scenes, rather than us just calling this
242 up front? -->
243 <!-- we've tried to clarify below /Carol -->
244
245 Rust substitutes the `*` operator with a call to the `deref` method and then a
246 plain dereference so that we don’t have to think about when we have to call the
247 `deref` method or not. This feature of Rust lets us write code that functions
248 identically whether we have a regular reference or a type that implements
249 `Deref`.
250
251 The reason the `deref` method returns a reference to a value, and why the plain
252 dereference outside the parentheses in `*(y.deref())` is still necessary, is
253 because of ownership. If the `deref` method returned the value directly instead
254 of a reference to the value, the value would be moved out of `self`. We don’t
255 want to take ownership of the inner value inside `MyBox<T>` in this case and in
256 most cases where we use the dereference operator.
257
258 Note that replacing `*` with a call to the `deref` method and then a call to
259 `*` happens once, each time we type a `*` in our code. The substitution of `*`
260 does not recurse infinitely. That’s how we end up with data of type `i32`,
261 which matches the `5` in the `assert_eq!` in Listing 15-11.
262
263 ### Implicit Deref Coercions with Functions and Methods
264
265 <!--Below -- "A deref coercion happens when..." So this isn't something the
266 reader is making happen, but something that just happens behind the scene? If
267 not, can you change this to an active tone? -->
268 <!-- Yes, it is something that happens behind the scenes, which is why we
269 describe it as implicit. /Carol -->
270
271 *Deref coercion* is a convenience that Rust performs on arguments to functions
272 and methods. Deref coercion converts a reference to a type that implements
273 `Deref` into a reference to a type that `Deref` can convert the original type
274 into. Deref coercion happens automatically when we pass a reference to a value
275 of a particular type as an argument to a function or method that doesn’t match
276 the type of the parameter in the function or method definition, and there’s a
277 sequence of calls to the `deref` method that will convert the type we provided
278 into the type that the parameter needs.
279
280 Deref coercion was added to Rust so that programmers writing function and
281 method calls don’t need to add as many explicit references and dereferences
282 with `&` and `*`. This feature also lets us write more code that can work for
283 either references or smart pointers.
284
285 To illustrate deref coercion in action, let’s use the `MyBox<T>` type we
286 defined in Listing 15-10 as well as the implementation of `Deref` that we added
287 in Listing 15-12. Listing 15-13 shows the definition of a function that has a
288 string slice parameter:
289
290 <span class="filename">Filename: src/main.rs</span>
291
292 ```rust
293 fn hello(name: &str) {
294 println!("Hello, {}!", name);
295 }
296 ```
297
298 <span class="caption">Listing 15-13: A `hello` function that has the parameter
299 `name` of type `&str`</span>
300
301 We can call the `hello` function with a string slice as an argument, like
302 `hello("Rust");` for example. Deref coercion makes it possible for us to call
303 `hello` with a reference to a value of type `MyBox<String>`, as shown in
304 Listing 15-14:
305
306 <span class="filename">Filename: src/main.rs</span>
307
308 ```rust
309 # use std::ops::Deref;
310 #
311 # struct MyBox<T>(T);
312 #
313 # impl<T> MyBox<T> {
314 # fn new(x: T) -> MyBox<T> {
315 # MyBox(x)
316 # }
317 # }
318 #
319 # impl<T> Deref for MyBox<T> {
320 # type Target = T;
321 #
322 # fn deref(&self) -> &T {
323 # &self.0
324 # }
325 # }
326 #
327 # fn hello(name: &str) {
328 # println!("Hello, {}!", name);
329 # }
330 #
331 fn main() {
332 let m = MyBox::new(String::from("Rust"));
333 hello(&m);
334 }
335 ```
336
337 <span class="caption">Listing 15-14: Calling `hello` with a reference to a
338 `MyBox<String>`, which works because of deref coercion</span>
339
340 Here we’re calling the `hello` function with the argument `&m`, which is a
341 reference to a `MyBox<String>` value. Because we implemented the `Deref` trait
342 on `MyBox<T>` in Listing 15-12, Rust can turn `&MyBox<String>` into `&String`
343 by calling `deref`. The standard library provides an implementation of `Deref`
344 on `String` that returns a string slice, which we can see in the API
345 documentation for `Deref`. Rust calls `deref` again to turn the `&String` into
346 `&str`, which matches the `hello` function’s definition.
347
348 If Rust didn’t implement deref coercion, in order to call `hello` with a value
349 of type `&MyBox<String>`, we’d have to write the code in Listing 15-15 instead
350 of the code in Listing 15-14:
351
352 <span class="filename">Filename: src/main.rs</span>
353
354 ```rust
355 # use std::ops::Deref;
356 #
357 # struct MyBox<T>(T);
358 #
359 # impl<T> MyBox<T> {
360 # fn new(x: T) -> MyBox<T> {
361 # MyBox(x)
362 # }
363 # }
364 #
365 # impl<T> Deref for MyBox<T> {
366 # type Target = T;
367 #
368 # fn deref(&self) -> &T {
369 # &self.0
370 # }
371 # }
372 #
373 # fn hello(name: &str) {
374 # println!("Hello, {}!", name);
375 # }
376 #
377 fn main() {
378 let m = MyBox::new(String::from("Rust"));
379 hello(&(*m)[..]);
380 }
381 ```
382
383 <span class="caption">Listing 15-15: The code we’d have to write if Rust didn’t
384 have deref coercion</span>
385
386 The `(*m)` is dereferencing the `MyBox<String>` into a `String`. Then the `&`
387 and `[..]` are taking a string slice of the `String` that is equal to the whole
388 string to match the signature of `hello`. The code without deref coercions is
389 harder to read, write, and understand with all of these symbols involved. Deref
390 coercion makes it so that Rust takes care of these conversions for us
391 automatically.
392
393 When the `Deref` trait is defined for the types involved, Rust will analyze the
394 types and use `Deref::deref` as many times as it needs in order to get a
395 reference to match the parameter’s type. This is resolved at compile time, so
396 there is no run-time penalty for taking advantage of deref coercion!
397
398 ### How Deref Coercion Interacts with Mutability
399
400 <!-- below: are we talking about any mutable references, or are we talking
401 about mutable generic types, below? Can you make sure it's clear throughout, I
402 wasn't 100% -->
403 <!-- I'm not sure what you're asking, *types* don't have the property of
404 mutability or immutability, it's the variables or references to *instances* of
405 those types that are mutable or immutable. Also the way to say "any mutable
406 reference" is with `&mut` and a generic type parameter. Is that what's
407 confusing? /Carol -->
408
409 Similar to how we use the `Deref` trait to override `*` on immutable
410 references, Rust provides a `DerefMut` trait for overriding `*` on mutable
411 references.
412
413 Rust does deref coercion when it finds types and trait implementations in three
414 cases:
415
416 <!-- Would it make sense to move this list to the start of the deref section?
417 -->
418 <!-- I don't think this list makes very much sense until you understand what
419 deref coercion *is*. Can you elaborate on why you think it should be moved to
420 the beginning? /Carol -->
421
422 * From `&T` to `&U` when `T: Deref<Target=U>`.
423 * From `&mut T` to `&mut U` when `T: DerefMut<Target=U>`.
424 * From `&mut T` to `&U` when `T: Deref<Target=U>`.
425
426 The first two cases are the same except for mutability. The first case says
427 that if you have a `&T`, and `T` implements `Deref` to some type `U`, you can
428 get a `&U` transparently. The second case states that the same deref coercion
429 happens for mutable references.
430
431 The last case is trickier: Rust will also coerce a mutable reference to an
432 immutable one. The reverse is *not* possible though: immutable references will
433 never coerce to mutable ones. Because of the borrowing rules, if you have a
434 mutable reference, that mutable reference must be the only reference to that
435 data (otherwise, the program wouldn’t compile). Converting one mutable
436 reference to one immutable reference will never break the borrowing rules.
437 Converting an immutable reference to a mutable reference would require that
438 there was only one immutable reference to that data, and the borrowing rules
439 don’t guarantee that. Therefore, Rust can’t make the assumption that converting
440 an immutable reference to a mutable reference is possible.
441
442 <!-- Why does it coerce to an immutable reference, and why cant it go the other
443 way?-->
444 <!-- Elaborated above /Carol-->