]> git.proxmox.com Git - rustc.git/blob - src/doc/book/src/ch15-02-deref.md
New upstream version 1.60.0+dfsg1
[rustc.git] / src / doc / book / src / ch15-02-deref.md
1 ## Treating Smart Pointers Like Regular References with the `Deref` Trait
2
3 Implementing the `Deref` trait allows you 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, you can write code that operates on
7 references and use that code with smart pointers too.
8
9 Let’s first look at how the dereference operator works with regular references.
10 Then we’ll try to define a custom type that behaves like `Box<T>`, and see why
11 the dereference operator doesn’t work like a reference on our newly defined
12 type. We’ll explore how implementing the `Deref` trait makes it possible for
13 smart pointers to work in ways similar to references. Then we’ll look at
14 Rust’s *deref coercion* feature and how it lets us work with either references
15 or smart pointers.
16
17 > Note: there’s one big difference between the `MyBox<T>` type we’re about to
18 > build and the real `Box<T>`: our version will not store its data on the heap.
19 > We are focusing this example on `Deref`, so where the data is actually stored
20 > is less important than the pointer-like behavior.
21
22 ### Following the Pointer to the Value with the Dereference Operator
23
24 A regular reference is a type of pointer, and one way to think of a pointer is
25 as an arrow to a value stored somewhere else. In Listing 15-6, we create a
26 reference to an `i32` value and then use the dereference operator to follow the
27 reference to the data:
28
29 <span class="filename">Filename: src/main.rs</span>
30
31 ```rust
32 {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-06/src/main.rs}}
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 ```console
49 {{#include ../listings/ch15-smart-pointers/output-only-01-comparing-to-reference/output.txt}}
50 ```
51
52 Comparing a number and a reference to a number isn’t allowed because they’re
53 different types. We must use the dereference operator to follow the reference
54 to the value it’s pointing to.
55
56 ### Using `Box<T>` Like a Reference
57
58 We can rewrite the code in Listing 15-6 to use a `Box<T>` instead of a
59 reference; the dereference operator will work as shown in Listing 15-7:
60
61 <span class="filename">Filename: src/main.rs</span>
62
63 ```rust
64 {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-07/src/main.rs}}
65 ```
66
67 <span class="caption">Listing 15-7: Using the dereference operator on a
68 `Box<i32>`</span>
69
70 The main difference between Listing 15-7 and Listing 15-6 is that here we set
71 `y` to be an instance of a box pointing to a copied value of `x` rather than a
72 reference pointing to the value of `x`. In the last assertion, we can use the
73 dereference operator to follow the box’s pointer in the same way that we did
74 when `y` was a reference. Next, we’ll explore what is special about `Box<T>`
75 that enables us to use the dereference operator by defining our own box type.
76
77 ### Defining Our Own Smart Pointer
78
79 Let’s build a smart pointer similar to the `Box<T>` type provided by the
80 standard library to experience how smart pointers behave differently from
81 references by default. Then we’ll look at how to add the ability to use the
82 dereference operator.
83
84 The `Box<T>` type is ultimately defined as a tuple struct with one element, so
85 Listing 15-8 defines a `MyBox<T>` type in the same way. We’ll also define a
86 `new` function to match the `new` function defined on `Box<T>`.
87
88 <span class="filename">Filename: src/main.rs</span>
89
90 ```rust
91 {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-08/src/main.rs:here}}
92 ```
93
94 <span class="caption">Listing 15-8: Defining a `MyBox<T>` type</span>
95
96 We define a struct named `MyBox` and declare a generic parameter `T`, because
97 we want our type to hold values of any type. The `MyBox` type is a tuple struct
98 with one element of type `T`. The `MyBox::new` function takes one parameter of
99 type `T` and returns a `MyBox` instance that holds the value passed in.
100
101 Let’s try adding the `main` function in Listing 15-7 to Listing 15-8 and
102 changing it to use the `MyBox<T>` type we’ve defined instead of `Box<T>`. The
103 code in Listing 15-9 won’t compile because Rust doesn’t know how to dereference
104 `MyBox`.
105
106 <span class="filename">Filename: src/main.rs</span>
107
108 ```rust,ignore,does_not_compile
109 {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-09/src/main.rs:here}}
110 ```
111
112 <span class="caption">Listing 15-9: Attempting to use `MyBox<T>` in the same
113 way we used references and `Box<T>`</span>
114
115 Here’s the resulting compilation error:
116
117 ```console
118 {{#include ../listings/ch15-smart-pointers/listing-15-09/output.txt}}
119 ```
120
121 Our `MyBox<T>` type can’t be dereferenced because we haven’t implemented that
122 ability on our type. To enable dereferencing with the `*` operator, we
123 implement the `Deref` trait.
124
125 ### Treating a Type Like a Reference by Implementing the `Deref` Trait
126
127 As discussed in the [“Implementing a Trait on a Type”][impl-trait]<!-- ignore
128 --> section of Chapter 10, to implement a trait, we need to provide
129 implementations for the trait’s required methods. The `Deref` trait, provided
130 by the standard library, requires us to implement one method named `deref` that
131 borrows `self` and returns a reference to the inner data. Listing 15-10
132 contains an implementation of `Deref` to add to the definition of `MyBox`:
133
134 <span class="filename">Filename: src/main.rs</span>
135
136 ```rust
137 {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-10/src/main.rs:here}}
138 ```
139
140 <span class="caption">Listing 15-10: Implementing `Deref` on `MyBox<T>`</span>
141
142 The `type Target = T;` syntax defines an associated type for the `Deref` trait
143 to use. Associated types are a slightly different way of declaring a generic
144 parameter, but you don’t need to worry about them for now; we’ll cover them in
145 more detail in Chapter 19.
146
147 We fill in the body of the `deref` method with `&self.0` so `deref` returns a
148 reference to the value we want to access with the `*` operator. Recall from the
149 [“Using Tuple Structs without Named Fields to Create Different
150 Types”][tuple-structs]<!-- ignore --> section of Chapter 5 that `.0` accesses
151 the first value in a tuple struct. The `main` function in Listing 15-9 that
152 calls `*` on the `MyBox<T>` value now compiles, and the assertions pass!
153
154 Without the `Deref` trait, the compiler can only dereference `&` references.
155 The `deref` method gives the compiler the ability to take a value of any type
156 that implements `Deref` and call the `deref` method to get a `&` reference that
157 it knows how to dereference.
158
159 When we entered `*y` in Listing 15-9, behind the scenes Rust actually ran this
160 code:
161
162 ```rust,ignore
163 *(y.deref())
164 ```
165
166 Rust substitutes the `*` operator with a call to the `deref` method and then a
167 plain dereference so we don’t have to think about whether or not we need to
168 call the `deref` method. This Rust feature lets us write code that functions
169 identically whether we have a regular reference or a type that implements
170 `Deref`.
171
172 The reason the `deref` method returns a reference to a value, and that the plain
173 dereference outside the parentheses in `*(y.deref())` is still necessary, is the
174 ownership system. If the `deref` method returned the value directly instead of
175 a reference to the value, the value would be moved out of `self`. We don’t want
176 to take ownership of the inner value inside `MyBox<T>` in this case or in most
177 cases where we use the dereference operator.
178
179 Note that the `*` operator is replaced with a call to the `deref` method and
180 then a call to the `*` operator just once, each time we use a `*` in our code.
181 Because the substitution of the `*` operator does not recurse infinitely, we
182 end up with data of type `i32`, which matches the `5` in `assert_eq!` in
183 Listing 15-9.
184
185 ### Implicit Deref Coercions with Functions and Methods
186
187 *Deref coercion* is a convenience that Rust performs on arguments to functions
188 and methods. Deref coercion works only on types that implement the `Deref`
189 trait. Deref coercion converts a reference to such a type into a reference to
190 another type. For example, deref coercion can convert `&String` to `&str`
191 because `String` implements the `Deref` trait such that it returns `&str`.
192 Deref coercion happens automatically when we pass a reference to a particular
193 type’s value as an argument to a function or method that doesn’t match the
194 parameter type in the function or method definition. A sequence of calls to the
195 `deref` method converts the type we provided into the type the parameter needs.
196
197 Deref coercion was added to Rust so that programmers writing function and
198 method calls don’t need to add as many explicit references and dereferences
199 with `&` and `*`. The deref coercion feature also lets us write more code that
200 can work for either references or smart pointers.
201
202 To see deref coercion in action, let’s use the `MyBox<T>` type we defined in
203 Listing 15-8 as well as the implementation of `Deref` that we added in Listing
204 15-10. Listing 15-11 shows the definition of a function that has a string slice
205 parameter:
206
207 <span class="filename">Filename: src/main.rs</span>
208
209 ```rust
210 {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-11/src/main.rs:here}}
211 ```
212
213 <span class="caption">Listing 15-11: A `hello` function that has the parameter
214 `name` of type `&str`</span>
215
216 We can call the `hello` function with a string slice as an argument, such as
217 `hello("Rust");` for example. Deref coercion makes it possible to call `hello`
218 with a reference to a value of type `MyBox<String>`, as shown in Listing 15-12:
219
220 <span class="filename">Filename: src/main.rs</span>
221
222 ```rust
223 {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-12/src/main.rs:here}}
224 ```
225
226 <span class="caption">Listing 15-12: Calling `hello` with a reference to a
227 `MyBox<String>` value, which works because of deref coercion</span>
228
229 Here we’re calling the `hello` function with the argument `&m`, which is a
230 reference to a `MyBox<String>` value. Because we implemented the `Deref` trait
231 on `MyBox<T>` in Listing 15-10, Rust can turn `&MyBox<String>` into `&String`
232 by calling `deref`. The standard library provides an implementation of `Deref`
233 on `String` that returns a string slice, and this is in the API documentation
234 for `Deref`. Rust calls `deref` again to turn the `&String` into `&str`, which
235 matches the `hello` function’s definition.
236
237 If Rust didn’t implement deref coercion, we would have to write the code in
238 Listing 15-13 instead of the code in Listing 15-12 to call `hello` with a value
239 of type `&MyBox<String>`.
240
241 <span class="filename">Filename: src/main.rs</span>
242
243 ```rust
244 {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-13/src/main.rs:here}}
245 ```
246
247 <span class="caption">Listing 15-13: The code we would have to write if Rust
248 didn’t have deref coercion</span>
249
250 The `(*m)` dereferences the `MyBox<String>` into a `String`. Then the `&` and
251 `[..]` take a string slice of the `String` that is equal to the whole string to
252 match the signature of `hello`. The code without deref coercions is harder to
253 read, write, and understand with all of these symbols involved. Deref coercion
254 allows Rust to handle these conversions for us automatically.
255
256 When the `Deref` trait is defined for the types involved, Rust will analyze the
257 types and use `Deref::deref` as many times as necessary to get a reference to
258 match the parameter’s type. The number of times that `Deref::deref` needs to be
259 inserted is resolved at compile time, so there is no runtime penalty for taking
260 advantage of deref coercion!
261
262 ### How Deref Coercion Interacts with Mutability
263
264 Similar to how you use the `Deref` trait to override the `*` operator on
265 immutable references, you can use the `DerefMut` trait to override the `*`
266 operator on mutable references.
267
268 Rust does deref coercion when it finds types and trait implementations in three
269 cases:
270
271 * From `&T` to `&U` when `T: Deref<Target=U>`
272 * From `&mut T` to `&mut U` when `T: DerefMut<Target=U>`
273 * From `&mut T` to `&U` when `T: Deref<Target=U>`
274
275 The first two cases are the same except for mutability. The first case states
276 that if you have a `&T`, and `T` implements `Deref` to some type `U`, you can
277 get a `&U` transparently. The second case states that the same deref coercion
278 happens for mutable references.
279
280 The third case is trickier: Rust will also coerce a mutable reference to an
281 immutable one. But the reverse is *not* possible: immutable references will
282 never coerce to mutable references. Because of the borrowing rules, if you have
283 a mutable reference, that mutable reference must be the only reference to that
284 data (otherwise, the program wouldn’t compile). Converting one mutable
285 reference to one immutable reference will never break the borrowing rules.
286 Converting an immutable reference to a mutable reference would require that the
287 initial immutable reference is the only immutable reference to that data, but
288 the borrowing rules don’t guarantee that. Therefore, Rust can’t make the
289 assumption that converting an immutable reference to a mutable reference is
290 possible.
291
292 [impl-trait]: ch10-02-traits.html#implementing-a-trait-on-a-type
293 [tuple-structs]: ch05-01-defining-structs.html#using-tuple-structs-without-named-fields-to-create-different-types