]> git.proxmox.com Git - rustc.git/blob - src/doc/book/src/ch19-03-advanced-traits.md
New upstream version 1.46.0~beta.2+dfsg1
[rustc.git] / src / doc / book / src / ch19-03-advanced-traits.md
1 ## Advanced Traits
2
3 We first covered traits in the [“Traits: Defining Shared
4 Behavior”][traits-defining-shared-behavior]<!-- ignore --> section of Chapter
5 10, but as with lifetimes, we didn’t discuss the more advanced details. Now
6 that you know more about Rust, we can get into the nitty-gritty.
7
8 ### Specifying Placeholder Types in Trait Definitions with Associated Types
9
10 *Associated types* connect a type placeholder with a trait such that the trait
11 method definitions can use these placeholder types in their signatures. The
12 implementor of a trait will specify the concrete type to be used in this type’s
13 place for the particular implementation. That way, we can define a trait that
14 uses some types without needing to know exactly what those types are until the
15 trait is implemented.
16
17 We’ve described most of the advanced features in this chapter as being rarely
18 needed. Associated types are somewhere in the middle: they’re used more rarely
19 than features explained in the rest of the book but more commonly than many of
20 the other features discussed in this chapter.
21
22 One example of a trait with an associated type is the `Iterator` trait that the
23 standard library provides. The associated type is named `Item` and stands in
24 for the type of the values the type implementing the `Iterator` trait is
25 iterating over. In [“The `Iterator` Trait and the `next`
26 Method”][the-iterator-trait-and-the-next-method]<!-- ignore --> section of
27 Chapter 13, we mentioned that the definition of the `Iterator` trait is as
28 shown in Listing 19-12.
29
30 ```rust
31 {{#rustdoc_include ../listings/ch19-advanced-features/listing-19-12/src/lib.rs}}
32 ```
33
34 <span class="caption">Listing 19-12: The definition of the `Iterator` trait
35 that has an associated type `Item`</span>
36
37 The type `Item` is a placeholder type, and the `next` method’s definition shows
38 that it will return values of type `Option<Self::Item>`. Implementors of the
39 `Iterator` trait will specify the concrete type for `Item`, and the `next`
40 method will return an `Option` containing a value of that concrete type.
41
42 Associated types might seem like a similar concept to generics, in that the
43 latter allow us to define a function without specifying what types it can
44 handle. So why use associated types?
45
46 Let’s examine the difference between the two concepts with an example from
47 Chapter 13 that implements the `Iterator` trait on the `Counter` struct. In
48 Listing 13-21, we specified that the `Item` type was `u32`:
49
50 <span class="filename">Filename: src/lib.rs</span>
51
52 ```rust,ignore
53 {{#rustdoc_include ../listings/ch19-advanced-features/listing-13-21-reproduced/src/lib.rs:ch19}}
54 ```
55
56 This syntax seems comparable to that of generics. So why not just define the
57 `Iterator` trait with generics, as shown in Listing 19-13?
58
59 ```rust
60 {{#rustdoc_include ../listings/ch19-advanced-features/listing-19-13/src/lib.rs}}
61 ```
62
63 <span class="caption">Listing 19-13: A hypothetical definition of the
64 `Iterator` trait using generics</span>
65
66 The difference is that when using generics, as in Listing 19-13, we must
67 annotate the types in each implementation; because we can also implement
68 `Iterator<String> for Counter` or any other type, we could have multiple
69 implementations of `Iterator` for `Counter`. In other words, when a trait has a
70 generic parameter, it can be implemented for a type multiple times, changing
71 the concrete types of the generic type parameters each time. When we use the
72 `next` method on `Counter`, we would have to provide type annotations to
73 indicate which implementation of `Iterator` we want to use.
74
75 With associated types, we don’t need to annotate types because we can’t
76 implement a trait on a type multiple times. In Listing 19-12 with the
77 definition that uses associated types, we can only choose what the type of
78 `Item` will be once, because there can only be one `impl Iterator for Counter`.
79 We don’t have to specify that we want an iterator of `u32` values everywhere
80 that we call `next` on `Counter`.
81
82 ### Default Generic Type Parameters and Operator Overloading
83
84 When we use generic type parameters, we can specify a default concrete type for
85 the generic type. This eliminates the need for implementors of the trait to
86 specify a concrete type if the default type works. The syntax for specifying a
87 default type for a generic type is `<PlaceholderType=ConcreteType>` when
88 declaring the generic type.
89
90 A great example of a situation where this technique is useful is with operator
91 overloading. *Operator overloading* is customizing the behavior of an operator
92 (such as `+`) in particular situations.
93
94 Rust doesn’t allow you to create your own operators or overload arbitrary
95 operators. But you can overload the operations and corresponding traits listed
96 in `std::ops` by implementing the traits associated with the operator. For
97 example, in Listing 19-14 we overload the `+` operator to add two `Point`
98 instances together. We do this by implementing the `Add` trait on a `Point`
99 struct:
100
101 <span class="filename">Filename: src/main.rs</span>
102
103 ```rust
104 {{#rustdoc_include ../listings/ch19-advanced-features/listing-19-14/src/main.rs}}
105 ```
106
107 <span class="caption">Listing 19-14: Implementing the `Add` trait to overload
108 the `+` operator for `Point` instances</span>
109
110 The `add` method adds the `x` values of two `Point` instances and the `y`
111 values of two `Point` instances to create a new `Point`. The `Add` trait has an
112 associated type named `Output` that determines the type returned from the `add`
113 method.
114
115 The default generic type in this code is within the `Add` trait. Here is its
116 definition:
117
118 ```rust
119 trait Add<Rhs=Self> {
120 type Output;
121
122 fn add(self, rhs: Rhs) -> Self::Output;
123 }
124 ```
125
126 This code should look generally familiar: a trait with one method and an
127 associated type. The new part is `Rhs=Self`: this syntax is called *default
128 type parameters*. The `Rhs` generic type parameter (short for “right hand
129 side”) defines the type of the `rhs` parameter in the `add` method. If we don’t
130 specify a concrete type for `Rhs` when we implement the `Add` trait, the type
131 of `Rhs` will default to `Self`, which will be the type we’re implementing
132 `Add` on.
133
134 When we implemented `Add` for `Point`, we used the default for `Rhs` because we
135 wanted to add two `Point` instances. Let’s look at an example of implementing
136 the `Add` trait where we want to customize the `Rhs` type rather than using the
137 default.
138
139 We have two structs, `Millimeters` and `Meters`, holding values in different
140 units. We want to add values in millimeters to values in meters and have the
141 implementation of `Add` do the conversion correctly. We can implement `Add` for
142 `Millimeters` with `Meters` as the `Rhs`, as shown in Listing 19-15.
143
144 <span class="filename">Filename: src/lib.rs</span>
145
146 ```rust
147 {{#rustdoc_include ../listings/ch19-advanced-features/listing-19-15/src/lib.rs}}
148 ```
149
150 <span class="caption">Listing 19-15: Implementing the `Add` trait on
151 `Millimeters` to add `Millimeters` to `Meters`</span>
152
153 To add `Millimeters` and `Meters`, we specify `impl Add<Meters>` to set the
154 value of the `Rhs` type parameter instead of using the default of `Self`.
155
156 You’ll use default type parameters in two main ways:
157
158 * To extend a type without breaking existing code
159 * To allow customization in specific cases most users won’t need
160
161 The standard library’s `Add` trait is an example of the second purpose:
162 usually, you’ll add two like types, but the `Add` trait provides the ability to
163 customize beyond that. Using a default type parameter in the `Add` trait
164 definition means you don’t have to specify the extra parameter most of the
165 time. In other words, a bit of implementation boilerplate isn’t needed, making
166 it easier to use the trait.
167
168 The first purpose is similar to the second but in reverse: if you want to add a
169 type parameter to an existing trait, you can give it a default to allow
170 extension of the functionality of the trait without breaking the existing
171 implementation code.
172
173 ### Fully Qualified Syntax for Disambiguation: Calling Methods with the Same Name
174
175 Nothing in Rust prevents a trait from having a method with the same name as
176 another trait’s method, nor does Rust prevent you from implementing both traits
177 on one type. It’s also possible to implement a method directly on the type with
178 the same name as methods from traits.
179
180 When calling methods with the same name, you’ll need to tell Rust which one you
181 want to use. Consider the code in Listing 19-16 where we’ve defined two traits,
182 `Pilot` and `Wizard`, that both have a method called `fly`. We then implement
183 both traits on a type `Human` that already has a method named `fly` implemented
184 on it. Each `fly` method does something different.
185
186 <span class="filename">Filename: src/main.rs</span>
187
188 ```rust
189 {{#rustdoc_include ../listings/ch19-advanced-features/listing-19-16/src/main.rs:here}}
190 ```
191
192 <span class="caption">Listing 19-16: Two traits are defined to have a `fly`
193 method and are implemented on the `Human` type, and a `fly` method is
194 implemented on `Human` directly</span>
195
196 When we call `fly` on an instance of `Human`, the compiler defaults to calling
197 the method that is directly implemented on the type, as shown in Listing 19-17.
198
199 <span class="filename">Filename: src/main.rs</span>
200
201 ```rust
202 {{#rustdoc_include ../listings/ch19-advanced-features/listing-19-17/src/main.rs:here}}
203 ```
204
205 <span class="caption">Listing 19-17: Calling `fly` on an instance of
206 `Human`</span>
207
208 Running this code will print `*waving arms furiously*`, showing that Rust
209 called the `fly` method implemented on `Human` directly.
210
211 To call the `fly` methods from either the `Pilot` trait or the `Wizard` trait,
212 we need to use more explicit syntax to specify which `fly` method we mean.
213 Listing 19-18 demonstrates this syntax.
214
215 <span class="filename">Filename: src/main.rs</span>
216
217 ```rust
218 {{#rustdoc_include ../listings/ch19-advanced-features/listing-19-18/src/main.rs:here}}
219 ```
220
221 <span class="caption">Listing 19-18: Specifying which trait’s `fly` method we
222 want to call</span>
223
224 Specifying the trait name before the method name clarifies to Rust which
225 implementation of `fly` we want to call. We could also write
226 `Human::fly(&person)`, which is equivalent to the `person.fly()` that we used
227 in Listing 19-18, but this is a bit longer to write if we don’t need to
228 disambiguate.
229
230 Running this code prints the following:
231
232 ```console
233 {{#include ../listings/ch19-advanced-features/listing-19-18/output.txt}}
234 ```
235
236 Because the `fly` method takes a `self` parameter, if we had two *types* that
237 both implement one *trait*, Rust could figure out which implementation of a
238 trait to use based on the type of `self`.
239
240 However, associated functions that are part of traits don’t have a `self`
241 parameter. When two types in the same scope implement that trait, Rust can’t
242 figure out which type you mean unless you use *fully qualified syntax*. For
243 example, the `Animal` trait in Listing 19-19 has the associated function
244 `baby_name`, the implementation of `Animal` for the struct `Dog`, and the
245 associated function `baby_name` defined on `Dog` directly.
246
247 <span class="filename">Filename: src/main.rs</span>
248
249 ```rust
250 {{#rustdoc_include ../listings/ch19-advanced-features/listing-19-19/src/main.rs}}
251 ```
252
253 <span class="caption">Listing 19-19: A trait with an associated function and a
254 type with an associated function of the same name that also implements the
255 trait</span>
256
257 This code is for an animal shelter that wants to name all puppies Spot, which
258 is implemented in the `baby_name` associated function that is defined on `Dog`.
259 The `Dog` type also implements the trait `Animal`, which describes
260 characteristics that all animals have. Baby dogs are called puppies, and that
261 is expressed in the implementation of the `Animal` trait on `Dog` in the
262 `baby_name` function associated with the `Animal` trait.
263
264 In `main`, we call the `Dog::baby_name` function, which calls the associated
265 function defined on `Dog` directly. This code prints the following:
266
267 ```console
268 {{#include ../listings/ch19-advanced-features/listing-19-19/output.txt}}
269 ```
270
271 This output isn’t what we wanted. We want to call the `baby_name` function that
272 is part of the `Animal` trait that we implemented on `Dog` so the code prints
273 `A baby dog is called a puppy`. The technique of specifying the trait name that
274 we used in Listing 19-18 doesn’t help here; if we change `main` to the code in
275 Listing 19-20, we’ll get a compilation error.
276
277 <span class="filename">Filename: src/main.rs</span>
278
279 ```rust,ignore,does_not_compile
280 {{#rustdoc_include ../listings/ch19-advanced-features/listing-19-20/src/main.rs:here}}
281 ```
282
283 <span class="caption">Listing 19-20: Attempting to call the `baby_name`
284 function from the `Animal` trait, but Rust doesn’t know which implementation to
285 use</span>
286
287 Because `Animal::baby_name` is an associated function rather than a method, and
288 thus doesn’t have a `self` parameter, Rust can’t figure out which
289 implementation of `Animal::baby_name` we want. We’ll get this compiler error:
290
291 ```console
292 {{#include ../listings/ch19-advanced-features/listing-19-20/output.txt}}
293 ```
294
295 To disambiguate and tell Rust that we want to use the implementation of
296 `Animal` for `Dog`, we need to use fully qualified syntax. Listing 19-21
297 demonstrates how to use fully qualified syntax.
298
299 <span class="filename">Filename: src/main.rs</span>
300
301 ```rust
302 {{#rustdoc_include ../listings/ch19-advanced-features/listing-19-21/src/main.rs:here}}
303 ```
304
305 <span class="caption">Listing 19-21: Using fully qualified syntax to specify
306 that we want to call the `baby_name` function from the `Animal` trait as
307 implemented on `Dog`</span>
308
309 We’re providing Rust with a type annotation within the angle brackets, which
310 indicates we want to call the `baby_name` method from the `Animal` trait as
311 implemented on `Dog` by saying that we want to treat the `Dog` type as an
312 `Animal` for this function call. This code will now print what we want:
313
314 ```console
315 {{#include ../listings/ch19-advanced-features/listing-19-21/output.txt}}
316 ```
317
318 In general, fully qualified syntax is defined as follows:
319
320 ```rust,ignore
321 <Type as Trait>::function(receiver_if_method, next_arg, ...);
322 ```
323
324 For associated functions, there would not be a `receiver`: there would only be
325 the list of other arguments. You could use fully qualified syntax everywhere
326 that you call functions or methods. However, you’re allowed to omit any part of
327 this syntax that Rust can figure out from other information in the program. You
328 only need to use this more verbose syntax in cases where there are multiple
329 implementations that use the same name and Rust needs help to identify which
330 implementation you want to call.
331
332 ### Using Supertraits to Require One Trait’s Functionality Within Another Trait
333
334 Sometimes, you might need one trait to use another trait’s functionality. In
335 this case, you need to rely on the dependent trait also being implemented.
336 The trait you rely on is a *supertrait* of the trait you’re implementing.
337
338 For example, let’s say we want to make an `OutlinePrint` trait with an
339 `outline_print` method that will print a value framed in asterisks. That is,
340 given a `Point` struct that implements `Display` to result in `(x, y)`, when we
341 call `outline_print` on a `Point` instance that has `1` for `x` and `3` for
342 `y`, it should print the following:
343
344 ```text
345 **********
346 * *
347 * (1, 3) *
348 * *
349 **********
350 ```
351
352 In the implementation of `outline_print`, we want to use the `Display` trait’s
353 functionality. Therefore, we need to specify that the `OutlinePrint` trait will
354 work only for types that also implement `Display` and provide the functionality
355 that `OutlinePrint` needs. We can do that in the trait definition by specifying
356 `OutlinePrint: Display`. This technique is similar to adding a trait bound to
357 the trait. Listing 19-22 shows an implementation of the `OutlinePrint` trait.
358
359 <span class="filename">Filename: src/main.rs</span>
360
361 ```rust
362 {{#rustdoc_include ../listings/ch19-advanced-features/listing-19-22/src/main.rs:here}}
363 ```
364
365 <span class="caption">Listing 19-22: Implementing the `OutlinePrint` trait that
366 requires the functionality from `Display`</span>
367
368 Because we’ve specified that `OutlinePrint` requires the `Display` trait, we
369 can use the `to_string` function that is automatically implemented for any type
370 that implements `Display`. If we tried to use `to_string` without adding a
371 colon and specifying the `Display` trait after the trait name, we’d get an
372 error saying that no method named `to_string` was found for the type `&Self` in
373 the current scope.
374
375 Let’s see what happens when we try to implement `OutlinePrint` on a type that
376 doesn’t implement `Display`, such as the `Point` struct:
377
378 <span class="filename">Filename: src/main.rs</span>
379
380 ```rust,ignore,does_not_compile
381 {{#rustdoc_include ../listings/ch19-advanced-features/no-listing-02-impl-outlineprint-for-point/src/main.rs:here}}
382 ```
383
384 We get an error saying that `Display` is required but not implemented:
385
386 ```console
387 {{#include ../listings/ch19-advanced-features/no-listing-02-impl-outlineprint-for-point/output.txt}}
388 ```
389
390 To fix this, we implement `Display` on `Point` and satisfy the constraint that
391 `OutlinePrint` requires, like so:
392
393 <span class="filename">Filename: src/main.rs</span>
394
395 ```rust
396 {{#rustdoc_include ../listings/ch19-advanced-features/no-listing-03-impl-display-for-point/src/main.rs:here}}
397 ```
398
399 Then implementing the `OutlinePrint` trait on `Point` will compile
400 successfully, and we can call `outline_print` on a `Point` instance to display
401 it within an outline of asterisks.
402
403 ### Using the Newtype Pattern to Implement External Traits on External Types
404
405 In Chapter 10 in the [“Implementing a Trait on a
406 Type”][implementing-a-trait-on-a-type]<!-- ignore --> section, we mentioned
407 the orphan rule that states we’re allowed to implement a trait on a type as
408 long as either the trait or the type are local to our crate. It’s possible to
409 get around this restriction using the *newtype pattern*, which involves
410 creating a new type in a tuple struct. (We covered tuple structs in the
411 [“Using Tuple Structs without Named Fields to Create Different
412 Types”][tuple-structs]<!-- ignore --> section of Chapter 5.) The tuple struct
413 will have one field and be a thin wrapper around the type we want to implement
414 a trait for. Then the wrapper type is local to our crate, and we can implement
415 the trait on the wrapper. *Newtype* is a term that originates from the Haskell
416 programming language. There is no runtime performance penalty for using this
417 pattern, and the wrapper type is elided at compile time.
418
419 As an example, let’s say we want to implement `Display` on `Vec<T>`, which the
420 orphan rule prevents us from doing directly because the `Display` trait and the
421 `Vec<T>` type are defined outside our crate. We can make a `Wrapper` struct
422 that holds an instance of `Vec<T>`; then we can implement `Display` on
423 `Wrapper` and use the `Vec<T>` value, as shown in Listing 19-23.
424
425 <span class="filename">Filename: src/main.rs</span>
426
427 ```rust
428 {{#rustdoc_include ../listings/ch19-advanced-features/listing-19-23/src/main.rs}}
429 ```
430
431 <span class="caption">Listing 19-23: Creating a `Wrapper` type around
432 `Vec<String>` to implement `Display`</span>
433
434 The implementation of `Display` uses `self.0` to access the inner `Vec<T>`,
435 because `Wrapper` is a tuple struct and `Vec<T>` is the item at index 0 in the
436 tuple. Then we can use the functionality of the `Display` type on `Wrapper`.
437
438 The downside of using this technique is that `Wrapper` is a new type, so it
439 doesn’t have the methods of the value it’s holding. We would have to implement
440 all the methods of `Vec<T>` directly on `Wrapper` such that the methods
441 delegate to `self.0`, which would allow us to treat `Wrapper` exactly like a
442 `Vec<T>`. If we wanted the new type to have every method the inner type has,
443 implementing the `Deref` trait (discussed in Chapter 15 in the [“Treating Smart
444 Pointers Like Regular References with the `Deref`
445 Trait”][smart-pointer-deref]<!-- ignore --> section) on the `Wrapper` to return
446 the inner type would be a solution. If we don’t want the `Wrapper` type to have
447 all the methods of the inner type—for example, to restrict the `Wrapper` type’s
448 behavior—we would have to implement just the methods we do want manually.
449
450 Now you know how the newtype pattern is used in relation to traits; it’s also a
451 useful pattern even when traits are not involved. Let’s switch focus and look
452 at some advanced ways to interact with Rust’s type system.
453
454 [implementing-a-trait-on-a-type]:
455 ch10-02-traits.html#implementing-a-trait-on-a-type
456 [the-iterator-trait-and-the-next-method]:
457 ch13-02-iterators.html#the-iterator-trait-and-the-next-method
458 [traits-defining-shared-behavior]:
459 ch10-02-traits.html#traits-defining-shared-behavior
460 [smart-pointer-deref]: ch15-02-deref.html#treating-smart-pointers-like-regular-references-with-the-deref-trait
461 [tuple-structs]: ch05-01-defining-structs.html#using-tuple-structs-without-named-fields-to-create-different-types