]> git.proxmox.com Git - rustc.git/blob - src/doc/book/second-edition/src/ch15-02-deref.md
ecb8fa38f3809207e2ab6f0ad27e594b9befbdcf
[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 the `Deref` trait allows us to customize the behavior of the
4 *dereference operator*, `*` (as opposed to the multiplication or glob
5 operator). By implementing `Deref` in such a way that a smart pointer can be
6 treated like a regular reference, we can write code that operates on references
7 and use that code with smart pointers too.
8
9 Let’s first look at how `*` works with regular references, and then try to
10 define our own type like `Box<T>` and see why `*` doesn’t work like a reference
11 on our newly defined type. We’ll explore how implementing the `Deref` trait
12 makes it possible for smart pointers to work in a similar way as references.
13 Then we’ll look at Rust’s *deref coercion* feature and how it lets us work with
14 either references or smart pointers.
15
16 ### Following the Pointer to the Value with `*`
17
18 A regular reference is a type of pointer, and one way to think of a pointer is
19 as an arrow to a value stored somewhere else. In Listing 15-6, we create a
20 reference to an `i32` value and then use the dereference operator to follow the
21 reference to the data:
22
23 <span class="filename">Filename: src/main.rs</span>
24
25 ```rust
26 fn main() {
27 let x = 5;
28 let y = &x;
29
30 assert_eq!(5, x);
31 assert_eq!(5, *y);
32 }
33 ```
34
35 <span class="caption">Listing 15-6: Using the dereference operator to follow a
36 reference to an `i32` value</span>
37
38 The variable `x` holds an `i32` value, `5`. We set `y` equal to a reference to
39 `x`. We can assert that `x` is equal to `5`. However, if we want to make an
40 assertion about the value in `y`, we have to use `*y` to follow the reference
41 to the value it’s pointing to (hence *dereference*). Once we dereference `y`,
42 we have access to the integer value `y` is pointing to that we can compare with
43 `5`.
44
45 If we tried to write `assert_eq!(5, y);` instead, we would get this compilation
46 error:
47
48 ```text
49 error[E0277]: the trait bound `{integer}: std::cmp::PartialEq<&{integer}>` is
50 not satisfied
51 --> src/main.rs:6:5
52 |
53 6 | assert_eq!(5, y);
54 | ^^^^^^^^^^^^^^^^^ can't compare `{integer}` with `&{integer}`
55 |
56 = help: the trait `std::cmp::PartialEq<&{integer}>` is not implemented for
57 `{integer}`
58 ```
59
60 Comparing a number and a reference to a number isn’t allowed because they’re
61 different types. We must use `*` to follow the reference to the value it’s
62 pointing to.
63
64 ### Using `Box<T>` Like a Reference
65
66 We can rewrite the code in Listing 15-6 to use a `Box<T>` instead of a
67 reference, and the dereference operator will work the same way as shown in
68 Listing 15-7:
69
70 <span class="filename">Filename: src/main.rs</span>
71
72 ```rust
73 fn main() {
74 let x = 5;
75 let y = Box::new(x);
76
77 assert_eq!(5, x);
78 assert_eq!(5, *y);
79 }
80 ```
81
82 <span class="caption">Listing 15-7: Using the dereference operator on a
83 `Box<i32>`</span>
84
85 The only difference between Listing 15-7 and Listing 15-6 is that here we set
86 `y` to be an instance of a box pointing to the value in `x` rather than a
87 reference pointing to the value of `x`. In the last assertion, we can use the
88 dereference operator to follow the box’s pointer in the same way that we did
89 when `y` was a reference. Next, we’ll explore what is special about `Box<T>`
90 that enables us to use the dereference operator by defining our own box type.
91
92 ### Defining Our Own Smart Pointer
93
94 Let’s build a smart pointer similar to the `Box<T>` type provided by the
95 standard library to experience how smart pointers behave differently to
96 references by default. Then we’ll look at how to add the ability to use the
97 dereference operator.
98
99 The `Box<T>` type is ultimately defined as a tuple struct with one element, so
100 Listing 15-8 defines a `MyBox<T>` type in the same way. We’ll also define a
101 `new` function to match the `new` function defined on `Box<T>`:
102
103 <span class="filename">Filename: src/main.rs</span>
104
105 ```rust
106 struct MyBox<T>(T);
107
108 impl<T> MyBox<T> {
109 fn new(x: T) -> MyBox<T> {
110 MyBox(x)
111 }
112 }
113 ```
114
115 <span class="caption">Listing 15-8: Defining a `MyBox<T>` type</span>
116
117 We define a struct named `MyBox` and declare a generic parameter `T`, because
118 we want our type to hold values of any type. The `MyBox` type is a tuple struct
119 with one element of type `T`. The `MyBox::new` function takes one parameter of
120 type `T` and returns a `MyBox` instance that holds the value passed in.
121
122 Let’s try adding the `main` function in Listing 15-7 to Listing 15-8 and
123 changing it to use the `MyBox<T>` type we’ve defined instead of `Box<T>`. The
124 code in Listing 15-9 won’t compile because Rust doesn’t know how to dereference
125 `MyBox`:
126
127 <span class="filename">Filename: src/main.rs</span>
128
129 ```rust,ignore
130 fn main() {
131 let x = 5;
132 let y = MyBox::new(x);
133
134 assert_eq!(5, x);
135 assert_eq!(5, *y);
136 }
137 ```
138
139 <span class="caption">Listing 15-9: Attempting to use `MyBox<T>` in the same
140 way we used references and `Box<T>`</span>
141
142 Here’s the resulting compilation error:
143
144 ```text
145 error[E0614]: type `MyBox<{integer}>` cannot be dereferenced
146 --> src/main.rs:14:19
147 |
148 14 | assert_eq!(5, *y);
149 | ^^
150 ```
151
152 Our `MyBox<T>` type can’t be dereferenced because we haven’t implemented that
153 ability on our type. To enable dereferencing with the `*` operator, we
154 implement the `Deref` trait.
155
156 ### Treating a Type Like a Reference by Implementing the `Deref` Trait
157
158 As discussed in Chapter 10, to implement a trait, we need to provide
159 implementations for the trait’s required methods. The `Deref` trait, provided
160 by the standard library, requires us to implement one method named `deref` that
161 borrows `self` and returns a reference to the inner data. Listing 15-10
162 contains an implementation of `Deref` to add to the definition of `MyBox`:
163
164 <span class="filename">Filename: src/main.rs</span>
165
166 ```rust
167 use std::ops::Deref;
168
169 # struct MyBox<T>(T);
170 impl<T> Deref for MyBox<T> {
171 type Target = T;
172
173 fn deref(&self) -> &T {
174 &self.0
175 }
176 }
177 ```
178
179 <span class="caption">Listing 15-10: Implementing `Deref` on `MyBox<T>`</span>
180
181 The `type Target = T;` syntax defines an associated type for the `Deref` trait
182 to use. Associated types are a slightly different way of declaring a generic
183 parameter, but you don’t need to worry about them for now; we’ll cover them in
184 more detail in Chapter 19.
185
186 We fill in the body of the `deref` method with `&self.0` so `deref` returns a
187 reference to the value we want to access with the `*` operator. The `main`
188 function in Listing 15-9 that calls `*` on the `MyBox<T>` value now compiles
189 and the assertions pass!
190
191 Without the `Deref` trait, the compiler can only dereference `&` references.
192 The `deref` method gives the compiler the ability to take a value of any type
193 that implements `Deref` and call the `deref` method to get a `&` reference that
194 it knows how to dereference.
195
196 When we entered `*y` in Listing 15-9, behind the scenes Rust actually ran this
197 code:
198
199 ```rust,ignore
200 *(y.deref())
201 ```
202
203 Rust substitutes the `*` operator with a call to the `deref` method and then a
204 plain dereference so as programmers we don’t have to think about whether or not
205 we need to call the `deref` method. This Rust feature lets us write code that
206 functions identically whether we have a regular reference or a type that
207 implements `Deref`.
208
209 The reason the `deref` method returns a reference to a value and that the plain
210 dereference outside the parentheses in `*(y.deref())` is still necessary is due
211 to the ownership system. If the `deref` method returned the value directly
212 instead of a reference to the value, the value would be moved out of `self`. We
213 don’t want to take ownership of the inner value inside `MyBox<T>` in this case
214 and in most cases where we use the dereference operator.
215
216 Note that the `*` is replaced with a call to the `deref` method and then a call
217 to `*` just once, each time we type a `*` in our code. Because the substitution
218 of `*` does not recurse infinitely, we end up with data of type `i32`, which
219 matches the `5` in `assert_eq!` in Listing 15-9.
220
221 ### Implicit Deref Coercions with Functions and Methods
222
223 *Deref coercion* is a convenience that Rust performs on arguments to functions
224 and methods. Deref coercion converts a reference to a type that implements
225 `Deref` into a reference to a type that `Deref` can convert the original type
226 into. Deref coercion happens automatically when we pass a reference to a
227 particular type’s value as an argument to a function or method that doesn’t
228 match the parameter type in the function or method definition. A sequence of
229 calls to the `deref` method converts the type we provided into the type the
230 parameter needs.
231
232 Deref coercion was added to Rust so that programmers writing function and
233 method calls don’t need to add as many explicit references and dereferences
234 with `&` and `*`. The deref coercion feature also lets us write more code that
235 can work for either references or smart pointers.
236
237 To see deref coercion in action, let’s use the `MyBox<T>` type we defined in
238 Listing 15-8 as well as the implementation of `Deref` that we added in Listing
239 15-10. Listing 15-11 shows the definition of a function that has a string slice
240 parameter:
241
242 <span class="filename">Filename: src/main.rs</span>
243
244 ```rust
245 fn hello(name: &str) {
246 println!("Hello, {}!", name);
247 }
248 ```
249
250 <span class="caption">Listing 15-11: A `hello` function that has the parameter
251 `name` of type `&str`</span>
252
253 We can call the `hello` function with a string slice as an argument, such as
254 `hello("Rust");` for example. Deref coercion makes it possible to call `hello`
255 with a reference to a value of type `MyBox<String>`, as shown in Listing 15-12:
256
257 <span class="filename">Filename: src/main.rs</span>
258
259 ```rust
260 # use std::ops::Deref;
261 #
262 # struct MyBox<T>(T);
263 #
264 # impl<T> MyBox<T> {
265 # fn new(x: T) -> MyBox<T> {
266 # MyBox(x)
267 # }
268 # }
269 #
270 # impl<T> Deref for MyBox<T> {
271 # type Target = T;
272 #
273 # fn deref(&self) -> &T {
274 # &self.0
275 # }
276 # }
277 #
278 # fn hello(name: &str) {
279 # println!("Hello, {}!", name);
280 # }
281 #
282 fn main() {
283 let m = MyBox::new(String::from("Rust"));
284 hello(&m);
285 }
286 ```
287
288 <span class="caption">Listing 15-12: Calling `hello` with a reference to a
289 `MyBox<String>` value, which works because of deref coercion</span>
290
291 Here we’re calling the `hello` function with the argument `&m`, which is a
292 reference to a `MyBox<String>` value. Because we implemented the `Deref` trait
293 on `MyBox<T>` in Listing 15-10, Rust can turn `&MyBox<String>` into `&String`
294 by calling `deref`. The standard library provides an implementation of `Deref`
295 on `String` that returns a string slice, which is in the API documentation for
296 `Deref`. Rust calls `deref` again to turn the `&String` into `&str`, which
297 matches the `hello` function’s definition.
298
299 If Rust didn’t implement deref coercion, we would have to write the code in
300 Listing 15-13 instead of the code in Listing 15-12 to call `hello` with a value
301 of type `&MyBox<String>`:
302
303 <span class="filename">Filename: src/main.rs</span>
304
305 ```rust
306 # use std::ops::Deref;
307 #
308 # struct MyBox<T>(T);
309 #
310 # impl<T> MyBox<T> {
311 # fn new(x: T) -> MyBox<T> {
312 # MyBox(x)
313 # }
314 # }
315 #
316 # impl<T> Deref for MyBox<T> {
317 # type Target = T;
318 #
319 # fn deref(&self) -> &T {
320 # &self.0
321 # }
322 # }
323 #
324 # fn hello(name: &str) {
325 # println!("Hello, {}!", name);
326 # }
327 #
328 fn main() {
329 let m = MyBox::new(String::from("Rust"));
330 hello(&(*m)[..]);
331 }
332 ```
333
334 <span class="caption">Listing 15-13: The code we would have to write if Rust
335 didn’t have deref coercion</span>
336
337 The `(*m)` dereferences the `MyBox<String>` into a `String`. Then the `&` and
338 `[..]` take a string slice of the `String` that is equal to the whole string to
339 match the signature of `hello`. The code without deref coercions is harder to
340 read, write, and understand with all of these symbols involved. Deref coercion
341 allows Rust to handle these conversions for us automatically.
342
343 When the `Deref` trait is defined for the types involved, Rust will analyze the
344 types and use `Deref::deref` as many times as necessary to get a reference to
345 match the parameter’s type. The number of times that `Deref::deref` needs to be
346 inserted is resolved at compile time, so there is no runtime penalty for taking
347 advantage of deref coercion!
348
349 ### How Deref Coercion Interacts with Mutability
350
351 Similar to how we use the `Deref` trait to override `*` on immutable
352 references, Rust provides a `DerefMut` trait for overriding `*` on mutable
353 references.
354
355 Rust does deref coercion when it finds types and trait implementations in three
356 cases:
357
358 * From `&T` to `&U` when `T: Deref<Target=U>`
359 * From `&mut T` to `&mut U` when `T: DerefMut<Target=U>`
360 * From `&mut T` to `&U` when `T: Deref<Target=U>`
361
362 The first two cases are the same except for mutability. The first case states
363 that if you have a `&T`, and `T` implements `Deref` to some type `U`, you can
364 get a `&U` transparently. The second case states that the same deref coercion
365 happens for mutable references.
366
367 The third case is trickier: Rust will also coerce a mutable reference to an
368 immutable one. But the reverse is *not* possible: immutable references will
369 never coerce to mutable references. Because of the borrowing rules, if you have
370 a mutable reference, that mutable reference must be the only reference to that
371 data (otherwise, the program wouldn’t compile). Converting one mutable
372 reference to one immutable reference will never break the borrowing rules.
373 Converting an immutable reference to a mutable reference would require that
374 there is only one immutable reference to that data, and the borrowing rules
375 don’t guarantee that. Therefore, Rust can’t make the assumption that converting
376 an immutable reference to a mutable reference is possible.