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