]> git.proxmox.com Git - rustc.git/blob - src/doc/book/src/ch10-02-traits.md
New upstream version 1.44.1+dfsg1
[rustc.git] / src / doc / book / src / ch10-02-traits.md
1 ## Traits: Defining Shared Behavior
2
3 A *trait* tells the Rust compiler about functionality a particular type has and
4 can share with other types. We can use traits to define shared behavior in an
5 abstract way. We can use trait bounds to specify that a generic can be any type
6 that has certain behavior.
7
8 > Note: Traits are similar to a feature often called *interfaces* in other
9 > languages, although with some differences.
10
11 ### Defining a Trait
12
13 A type’s behavior consists of the methods we can call on that type. Different
14 types share the same behavior if we can call the same methods on all of those
15 types. Trait definitions are a way to group method signatures together to
16 define a set of behaviors necessary to accomplish some purpose.
17
18 For example, let’s say we have multiple structs that hold various kinds and
19 amounts of text: a `NewsArticle` struct that holds a news story filed in a
20 particular location and a `Tweet` that can have at most 280 characters along
21 with metadata that indicates whether it was a new tweet, a retweet, or a reply
22 to another tweet.
23
24 We want to make a media aggregator library that can display summaries of data
25 that might be stored in a `NewsArticle` or `Tweet` instance. To do this, we
26 need a summary from each type, and we need to request that summary by calling a
27 `summarize` method on an instance. Listing 10-12 shows the definition of a
28 `Summary` trait that expresses this behavior.
29
30 <span class="filename">Filename: src/lib.rs</span>
31
32 ```rust
33 {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-12/src/lib.rs}}
34 ```
35
36 <span class="caption">Listing 10-12: A `Summary` trait that consists of the
37 behavior provided by a `summarize` method</span>
38
39 Here, we declare a trait using the `trait` keyword and then the trait’s name,
40 which is `Summary` in this case. Inside the curly brackets, we declare the
41 method signatures that describe the behaviors of the types that implement this
42 trait, which in this case is `fn summarize(&self) -> String`.
43
44 After the method signature, instead of providing an implementation within curly
45 brackets, we use a semicolon. Each type implementing this trait must provide
46 its own custom behavior for the body of the method. The compiler will enforce
47 that any type that has the `Summary` trait will have the method `summarize`
48 defined with this signature exactly.
49
50 A trait can have multiple methods in its body: the method signatures are listed
51 one per line and each line ends in a semicolon.
52
53 ### Implementing a Trait on a Type
54
55 Now that we’ve defined the desired behavior using the `Summary` trait, we can
56 implement it on the types in our media aggregator. Listing 10-13 shows an
57 implementation of the `Summary` trait on the `NewsArticle` struct that uses the
58 headline, the author, and the location to create the return value of
59 `summarize`. For the `Tweet` struct, we define `summarize` as the username
60 followed by the entire text of the tweet, assuming that tweet content is
61 already limited to 280 characters.
62
63 <span class="filename">Filename: src/lib.rs</span>
64
65 ```rust
66 {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-13/src/lib.rs:here}}
67 ```
68
69 <span class="caption">Listing 10-13: Implementing the `Summary` trait on the
70 `NewsArticle` and `Tweet` types</span>
71
72 Implementing a trait on a type is similar to implementing regular methods. The
73 difference is that after `impl`, we put the trait name that we want to
74 implement, then use the `for` keyword, and then specify the name of the type we
75 want to implement the trait for. Within the `impl` block, we put the method
76 signatures that the trait definition has defined. Instead of adding a semicolon
77 after each signature, we use curly brackets and fill in the method body with
78 the specific behavior that we want the methods of the trait to have for the
79 particular type.
80
81 After implementing the trait, we can call the methods on instances of
82 `NewsArticle` and `Tweet` in the same way we call regular methods, like this:
83
84 ```rust,ignore
85 {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-01-calling-trait-method/src/main.rs:here}}
86 ```
87
88 This code prints `1 new tweet: horse_ebooks: of course, as you probably already
89 know, people`.
90
91 Note that because we defined the `Summary` trait and the `NewsArticle` and
92 `Tweet` types in the same *lib.rs* in Listing 10-13, they’re all in the same
93 scope. Let’s say this *lib.rs* is for a crate we’ve called `aggregator` and
94 someone else wants to use our crate’s functionality to implement the `Summary`
95 trait on a struct defined within their library’s scope. They would need to
96 bring the trait into their scope first. They would do so by specifying `use
97 aggregator::Summary;`, which then would enable them to implement `Summary` for
98 their type. The `Summary` trait would also need to be a public trait for
99 another crate to implement it, which it is because we put the `pub` keyword
100 before `trait` in Listing 10-12.
101
102 One restriction to note with trait implementations is that we can implement a
103 trait on a type only if either the trait or the type is local to our crate.
104 For example, we can implement standard library traits like `Display` on a
105 custom type like `Tweet` as part of our `aggregator` crate functionality,
106 because the type `Tweet` is local to our `aggregator` crate. We can also
107 implement `Summary` on `Vec<T>` in our `aggregator` crate, because the
108 trait `Summary` is local to our `aggregator` crate.
109
110 But we can’t implement external traits on external types. For example, we can’t
111 implement the `Display` trait on `Vec<T>` within our `aggregator` crate,
112 because `Display` and `Vec<T>` are defined in the standard library and aren’t
113 local to our `aggregator` crate. This restriction is part of a property of
114 programs called *coherence*, and more specifically the *orphan rule*, so named
115 because the parent type is not present. This rule ensures that other people’s
116 code can’t break your code and vice versa. Without the rule, two crates could
117 implement the same trait for the same type, and Rust wouldn’t know which
118 implementation to use.
119
120 ### Default Implementations
121
122 Sometimes it’s useful to have default behavior for some or all of the methods
123 in a trait instead of requiring implementations for all methods on every type.
124 Then, as we implement the trait on a particular type, we can keep or override
125 each method’s default behavior.
126
127 Listing 10-14 shows how to specify a default string for the `summarize` method
128 of the `Summary` trait instead of only defining the method signature, as we did
129 in Listing 10-12.
130
131 <span class="filename">Filename: src/lib.rs</span>
132
133 ```rust
134 {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-14/src/lib.rs:here}}
135 ```
136
137 <span class="caption">Listing 10-14: Definition of a `Summary` trait with a
138 default implementation of the `summarize` method</span>
139
140 To use a default implementation to summarize instances of `NewsArticle` instead
141 of defining a custom implementation, we specify an empty `impl` block with
142 `impl Summary for NewsArticle {}`.
143
144 Even though we’re no longer defining the `summarize` method on `NewsArticle`
145 directly, we’ve provided a default implementation and specified that
146 `NewsArticle` implements the `Summary` trait. As a result, we can still call
147 the `summarize` method on an instance of `NewsArticle`, like this:
148
149 ```rust,ignore
150 {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-02-calling-default-impl/src/main.rs:here}}
151 ```
152
153 This code prints `New article available! (Read more...)`.
154
155 Creating a default implementation for `summarize` doesn’t require us to change
156 anything about the implementation of `Summary` on `Tweet` in Listing 10-13. The
157 reason is that the syntax for overriding a default implementation is the same
158 as the syntax for implementing a trait method that doesn’t have a default
159 implementation.
160
161 Default implementations can call other methods in the same trait, even if those
162 other methods don’t have a default implementation. In this way, a trait can
163 provide a lot of useful functionality and only require implementors to specify
164 a small part of it. For example, we could define the `Summary` trait to have a
165 `summarize_author` method whose implementation is required, and then define a
166 `summarize` method that has a default implementation that calls the
167 `summarize_author` method:
168
169 ```rust
170 {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-03-default-impl-calls-other-methods/src/lib.rs:here}}
171 ```
172
173 To use this version of `Summary`, we only need to define `summarize_author`
174 when we implement the trait on a type:
175
176 ```rust,ignore
177 {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-03-default-impl-calls-other-methods/src/lib.rs:impl}}
178 ```
179
180 After we define `summarize_author`, we can call `summarize` on instances of the
181 `Tweet` struct, and the default implementation of `summarize` will call the
182 definition of `summarize_author` that we’ve provided. Because we’ve implemented
183 `summarize_author`, the `Summary` trait has given us the behavior of the
184 `summarize` method without requiring us to write any more code.
185
186 ```rust,ignore
187 {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-03-default-impl-calls-other-methods/src/main.rs:here}}
188 ```
189
190 This code prints `1 new tweet: (Read more from @horse_ebooks...)`.
191
192 Note that it isn’t possible to call the default implementation from an
193 overriding implementation of that same method.
194
195 ### Traits as Parameters
196
197 Now that you know how to define and implement traits, we can explore how to use
198 traits to define functions that accept many different types.
199
200 For example, in Listing 10-13, we implemented the `Summary` trait on the
201 `NewsArticle` and `Tweet` types. We can define a `notify` function that calls
202 the `summarize` method on its `item` parameter, which is of some type that
203 implements the `Summary` trait. To do this, we can use the `impl Trait`
204 syntax, like this:
205
206 ```rust,ignore
207 {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-04-traits-as-parameters/src/lib.rs:here}}
208 ```
209
210 Instead of a concrete type for the `item` parameter, we specify the `impl`
211 keyword and the trait name. This parameter accepts any type that implements the
212 specified trait. In the body of `notify`, we can call any methods on `item`
213 that come from the `Summary` trait, such as `summarize`. We can call `notify`
214 and pass in any instance of `NewsArticle` or `Tweet`. Code that calls the
215 function with any other type, such as a `String` or an `i32`, won’t compile
216 because those types don’t implement `Summary`.
217
218 #### Trait Bound Syntax
219
220 The `impl Trait` syntax works for straightforward cases but is actually
221 syntax sugar for a longer form, which is called a *trait bound*; it looks like
222 this:
223
224 ```rust,ignore
225 pub fn notify<T: Summary>(item: &T) {
226 println!("Breaking news! {}", item.summarize());
227 }
228 ```
229
230 This longer form is equivalent to the example in the previous section but is
231 more verbose. We place trait bounds with the declaration of the generic type
232 parameter after a colon and inside angle brackets.
233
234 The `impl Trait` syntax is convenient and makes for more concise code in simple
235 cases. The trait bound syntax can express more complexity in other cases. For
236 example, we can have two parameters that implement `Summary`. Using the `impl
237 Trait` syntax looks like this:
238
239 ```rust,ignore
240 pub fn notify(item1: &impl Summary, item2: &impl Summary) {
241 ```
242
243 If we wanted this function to allow `item1` and `item2` to have different
244 types, using `impl Trait` would be appropriate (as long as both types implement
245 `Summary`). If we wanted to force both parameters to have the same type, that’s
246 only possible to express using a trait bound, like this:
247
248 ```rust,ignore
249 pub fn notify<T: Summary>(item1: &T, item2: &T) {
250 ```
251
252 The generic type `T` specified as the type of the `item1` and `item2`
253 parameters constrains the function such that the concrete type of the value
254 passed as an argument for `item1` and `item2` must be the same.
255
256 #### Specifying Multiple Trait Bounds with the `+` Syntax
257
258 We can also specify more than one trait bound. Say we wanted `notify` to use
259 display formatting on `item` as well as the `summarize` method: we specify in
260 the `notify` definition that `item` must implement both `Display` and
261 `Summary`. We can do so using the `+` syntax:
262
263 ```rust,ignore
264 pub fn notify(item: &(impl Summary + Display)) {
265 ```
266
267 The `+` syntax is also valid with trait bounds on generic types:
268
269 ```rust,ignore
270 pub fn notify<T: Summary + Display>(item: &T) {
271 ```
272
273 With the two trait bounds specified, the body of `notify` can call `summarize`
274 and use `{}` to format `item`.
275
276 #### Clearer Trait Bounds with `where` Clauses
277
278 Using too many trait bounds has its downsides. Each generic has its own trait
279 bounds, so functions with multiple generic type parameters can contain lots of
280 trait bound information between the function’s name and its parameter list,
281 making the function signature hard to read. For this reason, Rust has alternate
282 syntax for specifying trait bounds inside a `where` clause after the function
283 signature. So instead of writing this:
284
285 ```rust,ignore
286 fn some_function<T: Display + Clone, U: Clone + Debug>(t: &T, u: &U) -> i32 {
287 ```
288
289 we can use a `where` clause, like this:
290
291 ```rust,ignore
292 fn some_function<T, U>(t: &T, u: &U) -> i32
293 where T: Display + Clone,
294 U: Clone + Debug
295 {
296 ```
297
298 This function’s signature is less cluttered: the function name, parameter list,
299 and return type are close together, similar to a function without lots of trait
300 bounds.
301
302 ### Returning Types that Implement Traits
303
304 We can also use the `impl Trait` syntax in the return position to return a
305 value of some type that implements a trait, as shown here:
306
307 ```rust,ignore
308 {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-05-returning-impl-trait/src/lib.rs:here}}
309 ```
310
311 By using `impl Summary` for the return type, we specify that the
312 `returns_summarizable` function returns some type that implements the `Summary`
313 trait without naming the concrete type. In this case, `returns_summarizable`
314 returns a `Tweet`, but the code calling this function doesn’t know that.
315
316 The ability to return a type that is only specified by the trait it implements
317 is especially useful in the context of closures and iterators, which we cover
318 in Chapter 13. Closures and iterators create types that only the compiler knows
319 or types that are very long to specify. The `impl Trait` syntax lets you
320 concisely specify that a function returns some type that implements the
321 `Iterator` trait without needing to write out a very long type.
322
323 However, you can only use `impl Trait` if you’re returning a single type. For
324 example, this code that returns either a `NewsArticle` or a `Tweet` with the
325 return type specified as `impl Summary` wouldn’t work:
326
327 ```rust,ignore,does_not_compile
328 {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-06-impl-trait-returns-one-type/src/lib.rs:here}}
329 ```
330
331 Returning either a `NewsArticle` or a `Tweet` isn’t allowed due to restrictions
332 around how the `impl Trait` syntax is implemented in the compiler. We’ll cover
333 how to write a function with this behavior in the [“Using Trait Objects That
334 Allow for Values of Different
335 Types”][using-trait-objects-that-allow-for-values-of-different-types]<!--
336 ignore --> section of Chapter 17.
337
338 ### Fixing the `largest` Function with Trait Bounds
339
340 Now that you know how to specify the behavior you want to use using the generic
341 type parameter’s bounds, let’s return to Listing 10-5 to fix the definition of
342 the `largest` function that uses a generic type parameter! Last time we tried
343 to run that code, we received this error:
344
345 ```text
346 {{#include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/output.txt}}
347 ```
348
349 In the body of `largest` we wanted to compare two values of type `T` using the
350 greater than (`>`) operator. Because that operator is defined as a default
351 method on the standard library trait `std::cmp::PartialOrd`, we need to specify
352 `PartialOrd` in the trait bounds for `T` so the `largest` function can work on
353 slices of any type that we can compare. We don’t need to bring `PartialOrd`
354 into scope because it’s in the prelude. Change the signature of `largest` to
355 look like this:
356
357 ```rust,ignore
358 {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/src/main.rs:here}}
359 ```
360
361 This time when we compile the code, we get a different set of errors:
362
363 ```text
364 {{#include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-fixing-listing-10-05/output.txt}}
365 ```
366
367 The key line in this error is `cannot move out of type [T], a non-copy slice`.
368 With our non-generic versions of the `largest` function, we were only trying to
369 find the largest `i32` or `char`. As discussed in the [“Stack-Only Data:
370 Copy”][stack-only-data-copy]<!-- ignore --> section in Chapter 4, types like
371 `i32` and `char` that have a known size can be stored on the stack, so they
372 implement the `Copy` trait. But when we made the `largest` function generic,
373 it became possible for the `list` parameter to have types in it that don’t
374 implement the `Copy` trait. Consequently, we wouldn’t be able to move the
375 value out of `list[0]` and into the `largest` variable, resulting in this
376 error.
377
378 To call this code with only those types that implement the `Copy` trait, we can
379 add `Copy` to the trait bounds of `T`! Listing 10-15 shows the complete code of
380 a generic `largest` function that will compile as long as the types of the
381 values in the slice that we pass into the function implement the `PartialOrd`
382 *and* `Copy` traits, like `i32` and `char` do.
383
384 <span class="filename">Filename: src/main.rs</span>
385
386 ```rust
387 {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-15/src/main.rs}}
388 ```
389
390 <span class="caption">Listing 10-15: A working definition of the `largest`
391 function that works on any generic type that implements the `PartialOrd` and
392 `Copy` traits</span>
393
394 If we don’t want to restrict the `largest` function to the types that implement
395 the `Copy` trait, we could specify that `T` has the trait bound `Clone` instead
396 of `Copy`. Then we could clone each value in the slice when we want the
397 `largest` function to have ownership. Using the `clone` function means we’re
398 potentially making more heap allocations in the case of types that own heap
399 data like `String`, and heap allocations can be slow if we’re working with
400 large amounts of data.
401
402 Another way we could implement `largest` is for the function to return a
403 reference to a `T` value in the slice. If we change the return type to `&T`
404 instead of `T`, thereby changing the body of the function to return a
405 reference, we wouldn’t need the `Clone` or `Copy` trait bounds and we could
406 avoid heap allocations. Try implementing these alternate solutions on your own!
407
408 ### Using Trait Bounds to Conditionally Implement Methods
409
410 By using a trait bound with an `impl` block that uses generic type parameters,
411 we can implement methods conditionally for types that implement the specified
412 traits. For example, the type `Pair<T>` in Listing 10-16 always implements the
413 `new` function. But `Pair<T>` only implements the `cmp_display` method if its
414 inner type `T` implements the `PartialOrd` trait that enables comparison *and*
415 the `Display` trait that enables printing.
416
417 <span class="filename">Filename: src/lib.rs</span>
418
419 ```rust
420 {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-16/src/lib.rs}}
421 ```
422
423 <span class="caption">Listing 10-16: Conditionally implement methods on a
424 generic type depending on trait bounds</span>
425
426 We can also conditionally implement a trait for any type that implements
427 another trait. Implementations of a trait on any type that satisfies the trait
428 bounds are called *blanket implementations* and are extensively used in the
429 Rust standard library. For example, the standard library implements the
430 `ToString` trait on any type that implements the `Display` trait. The `impl`
431 block in the standard library looks similar to this code:
432
433 ```rust,ignore
434 impl<T: Display> ToString for T {
435 // --snip--
436 }
437 ```
438
439 Because the standard library has this blanket implementation, we can call the
440 `to_string` method defined by the `ToString` trait on any type that implements
441 the `Display` trait. For example, we can turn integers into their corresponding
442 `String` values like this because integers implement `Display`:
443
444 ```rust
445 let s = 3.to_string();
446 ```
447
448 Blanket implementations appear in the documentation for the trait in the
449 “Implementors” section.
450
451 Traits and trait bounds let us write code that uses generic type parameters to
452 reduce duplication but also specify to the compiler that we want the generic
453 type to have particular behavior. The compiler can then use the trait bound
454 information to check that all the concrete types used with our code provide the
455 correct behavior. In dynamically typed languages, we would get an error at
456 runtime if we called a method on a type which didn’t define the method. But Rust
457 moves these errors to compile time so we’re forced to fix the problems before
458 our code is even able to run. Additionally, we don’t have to write code that
459 checks for behavior at runtime because we’ve already checked at compile time.
460 Doing so improves performance without having to give up the flexibility of
461 generics.
462
463 Another kind of generic that we’ve already been using is called *lifetimes*.
464 Rather than ensuring that a type has the behavior we want, lifetimes ensure
465 that references are valid as long as we need them to be. Let’s look at how
466 lifetimes do that.
467
468 [stack-only-data-copy]:
469 ch04-01-what-is-ownership.html#stack-only-data-copy
470 [using-trait-objects-that-allow-for-values-of-different-types]:
471 ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types