]>
Commit | Line | Data |
---|---|---|
13cf67c4 XL |
1 | ## Traits: Defining Shared Behavior |
2 | ||
5e7ed085 FG |
3 | A *trait* defines functionality a particular type has and can share with other |
4 | types. We can use traits to define shared behavior in an abstract way. We can | |
5 | use *trait bounds* to specify that a generic type can be any type that has | |
6 | certain behavior. | |
13cf67c4 XL |
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 | ||
3c0e092e XL |
24 | We want to make a media aggregator library crate named `aggregator` that can |
25 | display summaries of data that might be stored in a `NewsArticle` or `Tweet` | |
26 | instance. To do this, we need a summary from each type, and we’ll request | |
27 | that summary by calling a `summarize` method on an instance. Listing 10-12 | |
28 | shows the definition of a public `Summary` trait that expresses this behavior. | |
13cf67c4 XL |
29 | |
30 | <span class="filename">Filename: src/lib.rs</span> | |
31 | ||
5869c6ff | 32 | ```rust,noplayground |
74b04a01 | 33 | {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-12/src/lib.rs}} |
13cf67c4 XL |
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, | |
3c0e092e XL |
40 | which is `Summary` in this case. We’ve also declared the trait as `pub` so that |
41 | crates depending on this crate can make use of this trait too, as we’ll see in | |
42 | a few examples. Inside the curly brackets, we declare the method signatures | |
43 | that describe the behaviors of the types that implement this trait, which in | |
44 | this case is `fn summarize(&self) -> String`. | |
13cf67c4 XL |
45 | |
46 | After the method signature, instead of providing an implementation within curly | |
47 | brackets, we use a semicolon. Each type implementing this trait must provide | |
48 | its own custom behavior for the body of the method. The compiler will enforce | |
49 | that any type that has the `Summary` trait will have the method `summarize` | |
50 | defined with this signature exactly. | |
51 | ||
52 | A trait can have multiple methods in its body: the method signatures are listed | |
53 | one per line and each line ends in a semicolon. | |
54 | ||
55 | ### Implementing a Trait on a Type | |
56 | ||
3c0e092e XL |
57 | Now that we’ve defined the desired signatures of the `Summary` trait’s methods, |
58 | we can implement it on the types in our media aggregator. Listing 10-13 shows | |
59 | an implementation of the `Summary` trait on the `NewsArticle` struct that uses | |
60 | the headline, the author, and the location to create the return value of | |
13cf67c4 XL |
61 | `summarize`. For the `Tweet` struct, we define `summarize` as the username |
62 | followed by the entire text of the tweet, assuming that tweet content is | |
63 | already limited to 280 characters. | |
64 | ||
65 | <span class="filename">Filename: src/lib.rs</span> | |
66 | ||
5869c6ff | 67 | ```rust,noplayground |
74b04a01 | 68 | {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-13/src/lib.rs:here}} |
13cf67c4 XL |
69 | ``` |
70 | ||
71 | <span class="caption">Listing 10-13: Implementing the `Summary` trait on the | |
72 | `NewsArticle` and `Tweet` types</span> | |
73 | ||
74 | Implementing a trait on a type is similar to implementing regular methods. The | |
5e7ed085 FG |
75 | difference is that after `impl`, we put the trait name we want to implement, |
76 | then use the `for` keyword, and then specify the name of the type we want to | |
77 | implement the trait for. Within the `impl` block, we put the method signatures | |
78 | that the trait definition has defined. Instead of adding a semicolon after each | |
79 | signature, we use curly brackets and fill in the method body with the specific | |
80 | behavior that we want the methods of the trait to have for the particular type. | |
13cf67c4 | 81 | |
3c0e092e XL |
82 | Now that the library has implemented the `Summary` trait on `NewsArticle` and |
83 | `Tweet`, users of the crate can call the trait methods on instances of | |
84 | `NewsArticle` and `Tweet` in the same way we call regular methods. The only | |
5e7ed085 FG |
85 | difference is that the user must bring the trait into scope as well as the |
86 | types. Here’s an example of how a binary crate could use our `aggregator` | |
87 | library crate: | |
13cf67c4 XL |
88 | |
89 | ```rust,ignore | |
3c0e092e | 90 | {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-01-calling-trait-method/src/main.rs}} |
13cf67c4 XL |
91 | ``` |
92 | ||
93 | This code prints `1 new tweet: horse_ebooks: of course, as you probably already | |
94 | know, people`. | |
95 | ||
3c0e092e | 96 | Other crates that depend on the `aggregator` crate can also bring the `Summary` |
5e7ed085 FG |
97 | trait into scope to implement `Summary` on their own types. One restriction to |
98 | note is that we can implement a trait on a type only if at least one of the | |
99 | trait or the type is local to our crate. For example, we can implement standard | |
100 | library traits like `Display` on a custom type like `Tweet` as part of our | |
101 | `aggregator` crate functionality, because the type `Tweet` is local to our | |
102 | `aggregator` crate. We can also implement `Summary` on `Vec<T>` in our | |
103 | `aggregator` crate, because the trait `Summary` is local to our `aggregator` | |
104 | crate. | |
13cf67c4 XL |
105 | |
106 | But we can’t implement external traits on external types. For example, we can’t | |
107 | implement the `Display` trait on `Vec<T>` within our `aggregator` crate, | |
5e7ed085 FG |
108 | because `Display` and `Vec<T>` are both defined in the standard library and |
109 | aren’t local to our `aggregator` crate. This restriction is part of a property | |
110 | called *coherence*, and more specifically the *orphan rule*, so named because | |
111 | the parent type is not present. This rule ensures that other people’s code | |
112 | can’t break your code and vice versa. Without the rule, two crates could | |
13cf67c4 XL |
113 | implement the same trait for the same type, and Rust wouldn’t know which |
114 | implementation to use. | |
115 | ||
116 | ### Default Implementations | |
117 | ||
118 | Sometimes it’s useful to have default behavior for some or all of the methods | |
119 | in a trait instead of requiring implementations for all methods on every type. | |
120 | Then, as we implement the trait on a particular type, we can keep or override | |
121 | each method’s default behavior. | |
122 | ||
5e7ed085 FG |
123 | In Listing 10-14 we specify a default string for the `summarize` method of the |
124 | `Summary` trait instead of only defining the method signature, as we did in | |
125 | Listing 10-12. | |
13cf67c4 XL |
126 | |
127 | <span class="filename">Filename: src/lib.rs</span> | |
128 | ||
5869c6ff | 129 | ```rust,noplayground |
74b04a01 | 130 | {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-14/src/lib.rs:here}} |
13cf67c4 XL |
131 | ``` |
132 | ||
5e7ed085 FG |
133 | <span class="caption">Listing 10-14: Defining a `Summary` trait with a default |
134 | implementation of the `summarize` method</span> | |
13cf67c4 | 135 | |
5e7ed085 FG |
136 | To use a default implementation to summarize instances of `NewsArticle`, we |
137 | specify an empty `impl` block with `impl Summary for NewsArticle {}`. | |
13cf67c4 XL |
138 | |
139 | Even though we’re no longer defining the `summarize` method on `NewsArticle` | |
140 | directly, we’ve provided a default implementation and specified that | |
141 | `NewsArticle` implements the `Summary` trait. As a result, we can still call | |
142 | the `summarize` method on an instance of `NewsArticle`, like this: | |
143 | ||
144 | ```rust,ignore | |
74b04a01 | 145 | {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-02-calling-default-impl/src/main.rs:here}} |
13cf67c4 XL |
146 | ``` |
147 | ||
148 | This code prints `New article available! (Read more...)`. | |
149 | ||
5e7ed085 FG |
150 | Creating a default implementation doesn’t require us to change anything about |
151 | the implementation of `Summary` on `Tweet` in Listing 10-13. The reason is that | |
152 | the syntax for overriding a default implementation is the same as the syntax | |
153 | for implementing a trait method that doesn’t have a default implementation. | |
13cf67c4 XL |
154 | |
155 | Default implementations can call other methods in the same trait, even if those | |
156 | other methods don’t have a default implementation. In this way, a trait can | |
157 | provide a lot of useful functionality and only require implementors to specify | |
158 | a small part of it. For example, we could define the `Summary` trait to have a | |
159 | `summarize_author` method whose implementation is required, and then define a | |
160 | `summarize` method that has a default implementation that calls the | |
161 | `summarize_author` method: | |
162 | ||
5869c6ff | 163 | ```rust,noplayground |
74b04a01 | 164 | {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-03-default-impl-calls-other-methods/src/lib.rs:here}} |
13cf67c4 XL |
165 | ``` |
166 | ||
167 | To use this version of `Summary`, we only need to define `summarize_author` | |
168 | when we implement the trait on a type: | |
169 | ||
170 | ```rust,ignore | |
74b04a01 | 171 | {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-03-default-impl-calls-other-methods/src/lib.rs:impl}} |
13cf67c4 XL |
172 | ``` |
173 | ||
174 | After we define `summarize_author`, we can call `summarize` on instances of the | |
175 | `Tweet` struct, and the default implementation of `summarize` will call the | |
176 | definition of `summarize_author` that we’ve provided. Because we’ve implemented | |
177 | `summarize_author`, the `Summary` trait has given us the behavior of the | |
178 | `summarize` method without requiring us to write any more code. | |
179 | ||
180 | ```rust,ignore | |
74b04a01 | 181 | {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-03-default-impl-calls-other-methods/src/main.rs:here}} |
13cf67c4 XL |
182 | ``` |
183 | ||
184 | This code prints `1 new tweet: (Read more from @horse_ebooks...)`. | |
185 | ||
186 | Note that it isn’t possible to call the default implementation from an | |
187 | overriding implementation of that same method. | |
188 | ||
9fa01778 | 189 | ### Traits as Parameters |
13cf67c4 | 190 | |
532ac7d7 | 191 | Now that you know how to define and implement traits, we can explore how to use |
5e7ed085 FG |
192 | traits to define functions that accept many different types. We'll use the |
193 | `Summary` trait we implemented on the `NewsArticle` and `Tweet` types in | |
194 | Listing 10-13 to define a `notify` function that calls the `summarize` method | |
195 | on its `item` parameter, which is of some type that implements the `Summary` | |
196 | trait. To do this, we use the `impl Trait` syntax, like this: | |
13cf67c4 XL |
197 | |
198 | ```rust,ignore | |
74b04a01 | 199 | {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-04-traits-as-parameters/src/lib.rs:here}} |
13cf67c4 XL |
200 | ``` |
201 | ||
9fa01778 | 202 | Instead of a concrete type for the `item` parameter, we specify the `impl` |
532ac7d7 XL |
203 | keyword and the trait name. This parameter accepts any type that implements the |
204 | specified trait. In the body of `notify`, we can call any methods on `item` | |
205 | that come from the `Summary` trait, such as `summarize`. We can call `notify` | |
206 | and pass in any instance of `NewsArticle` or `Tweet`. Code that calls the | |
207 | function with any other type, such as a `String` or an `i32`, won’t compile | |
208 | because those types don’t implement `Summary`. | |
13cf67c4 | 209 | |
923072b8 FG |
210 | <!-- Old headings. Do not remove or links may break. --> |
211 | <a id="fixing-the-largest-function-with-trait-bounds"></a> | |
212 | ||
9fa01778 | 213 | #### Trait Bound Syntax |
13cf67c4 | 214 | |
5e7ed085 FG |
215 | The `impl Trait` syntax works for straightforward cases but is actually syntax |
216 | sugar for a longer form known as a *trait bound*; it looks like this: | |
13cf67c4 XL |
217 | |
218 | ```rust,ignore | |
ba9703b0 | 219 | pub fn notify<T: Summary>(item: &T) { |
13cf67c4 XL |
220 | println!("Breaking news! {}", item.summarize()); |
221 | } | |
222 | ``` | |
223 | ||
532ac7d7 XL |
224 | This longer form is equivalent to the example in the previous section but is |
225 | more verbose. We place trait bounds with the declaration of the generic type | |
226 | parameter after a colon and inside angle brackets. | |
13cf67c4 | 227 | |
532ac7d7 | 228 | The `impl Trait` syntax is convenient and makes for more concise code in simple |
5e7ed085 FG |
229 | cases, while the fuller trait bound syntax can express more complexity in other |
230 | cases. For example, we can have two parameters that implement `Summary`. Doing | |
231 | so with the `impl Trait` syntax looks like this: | |
13cf67c4 XL |
232 | |
233 | ```rust,ignore | |
ba9703b0 | 234 | pub fn notify(item1: &impl Summary, item2: &impl Summary) { |
13cf67c4 XL |
235 | ``` |
236 | ||
5e7ed085 FG |
237 | Using `impl Trait` is appropriate if we want this function to allow `item1` and |
238 | `item2` to have different types (as long as both types implement `Summary`). If | |
239 | we want to force both parameters to have the same type, however, we must use a | |
240 | trait bound, like this: | |
13cf67c4 XL |
241 | |
242 | ```rust,ignore | |
ba9703b0 | 243 | pub fn notify<T: Summary>(item1: &T, item2: &T) { |
13cf67c4 XL |
244 | ``` |
245 | ||
9fa01778 XL |
246 | The generic type `T` specified as the type of the `item1` and `item2` |
247 | parameters constrains the function such that the concrete type of the value | |
248 | passed as an argument for `item1` and `item2` must be the same. | |
13cf67c4 | 249 | |
9fa01778 XL |
250 | #### Specifying Multiple Trait Bounds with the `+` Syntax |
251 | ||
532ac7d7 | 252 | We can also specify more than one trait bound. Say we wanted `notify` to use |
5e7ed085 FG |
253 | display formatting as well as `summarize` on `item`: we specify in the `notify` |
254 | definition that `item` must implement both `Display` and `Summary`. We can do | |
255 | so using the `+` syntax: | |
13cf67c4 XL |
256 | |
257 | ```rust,ignore | |
ba9703b0 | 258 | pub fn notify(item: &(impl Summary + Display)) { |
13cf67c4 XL |
259 | ``` |
260 | ||
9fa01778 | 261 | The `+` syntax is also valid with trait bounds on generic types: |
13cf67c4 XL |
262 | |
263 | ```rust,ignore | |
ba9703b0 | 264 | pub fn notify<T: Summary + Display>(item: &T) { |
13cf67c4 XL |
265 | ``` |
266 | ||
9fa01778 XL |
267 | With the two trait bounds specified, the body of `notify` can call `summarize` |
268 | and use `{}` to format `item`. | |
269 | ||
270 | #### Clearer Trait Bounds with `where` Clauses | |
13cf67c4 | 271 | |
532ac7d7 XL |
272 | Using too many trait bounds has its downsides. Each generic has its own trait |
273 | bounds, so functions with multiple generic type parameters can contain lots of | |
274 | trait bound information between the function’s name and its parameter list, | |
9fa01778 XL |
275 | making the function signature hard to read. For this reason, Rust has alternate |
276 | syntax for specifying trait bounds inside a `where` clause after the function | |
277 | signature. So instead of writing this: | |
13cf67c4 XL |
278 | |
279 | ```rust,ignore | |
ba9703b0 | 280 | fn some_function<T: Display + Clone, U: Clone + Debug>(t: &T, u: &U) -> i32 { |
13cf67c4 XL |
281 | ``` |
282 | ||
283 | we can use a `where` clause, like this: | |
284 | ||
285 | ```rust,ignore | |
ba9703b0 | 286 | fn some_function<T, U>(t: &T, u: &U) -> i32 |
13cf67c4 XL |
287 | where T: Display + Clone, |
288 | U: Clone + Debug | |
289 | { | |
290 | ``` | |
291 | ||
532ac7d7 XL |
292 | This function’s signature is less cluttered: the function name, parameter list, |
293 | and return type are close together, similar to a function without lots of trait | |
294 | bounds. | |
13cf67c4 | 295 | |
9fa01778 | 296 | ### Returning Types that Implement Traits |
13cf67c4 | 297 | |
532ac7d7 XL |
298 | We can also use the `impl Trait` syntax in the return position to return a |
299 | value of some type that implements a trait, as shown here: | |
13cf67c4 XL |
300 | |
301 | ```rust,ignore | |
74b04a01 | 302 | {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-05-returning-impl-trait/src/lib.rs:here}} |
13cf67c4 XL |
303 | ``` |
304 | ||
532ac7d7 XL |
305 | By using `impl Summary` for the return type, we specify that the |
306 | `returns_summarizable` function returns some type that implements the `Summary` | |
307 | trait without naming the concrete type. In this case, `returns_summarizable` | |
5e7ed085 | 308 | returns a `Tweet`, but the code calling this function doesn’t need to know that. |
13cf67c4 | 309 | |
5e7ed085 FG |
310 | The ability to specify a return type only by the trait it implements is |
311 | especially useful in the context of closures and iterators, which we cover in | |
312 | Chapter 13. Closures and iterators create types that only the compiler knows or | |
313 | types that are very long to specify. The `impl Trait` syntax lets you concisely | |
314 | specify that a function returns some type that implements the `Iterator` trait | |
315 | without needing to write out a very long type. | |
13cf67c4 | 316 | |
532ac7d7 XL |
317 | However, you can only use `impl Trait` if you’re returning a single type. For |
318 | example, this code that returns either a `NewsArticle` or a `Tweet` with the | |
319 | return type specified as `impl Summary` wouldn’t work: | |
13cf67c4 XL |
320 | |
321 | ```rust,ignore,does_not_compile | |
74b04a01 | 322 | {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-06-impl-trait-returns-one-type/src/lib.rs:here}} |
13cf67c4 XL |
323 | ``` |
324 | ||
532ac7d7 XL |
325 | Returning either a `NewsArticle` or a `Tweet` isn’t allowed due to restrictions |
326 | around how the `impl Trait` syntax is implemented in the compiler. We’ll cover | |
327 | how to write a function with this behavior in the [“Using Trait Objects That | |
328 | Allow for Values of Different | |
9fa01778 XL |
329 | Types”][using-trait-objects-that-allow-for-values-of-different-types]<!-- |
330 | ignore --> section of Chapter 17. | |
13cf67c4 | 331 | |
13cf67c4 XL |
332 | ### Using Trait Bounds to Conditionally Implement Methods |
333 | ||
334 | By using a trait bound with an `impl` block that uses generic type parameters, | |
335 | we can implement methods conditionally for types that implement the specified | |
923072b8 | 336 | traits. For example, the type `Pair<T>` in Listing 10-15 always implements the |
3c0e092e | 337 | `new` function to return a new instance of `Pair<T>` (recall from the |
5e7ed085 | 338 | [“Defining Methods”][methods]<!-- ignore --> section of Chapter 5 that `Self` |
3c0e092e XL |
339 | is a type alias for the type of the `impl` block, which in this case is |
340 | `Pair<T>`). But in the next `impl` block, `Pair<T>` only implements the | |
341 | `cmp_display` method if its inner type `T` implements the `PartialOrd` trait | |
342 | that enables comparison *and* the `Display` trait that enables printing. | |
13cf67c4 | 343 | |
74b04a01 | 344 | <span class="filename">Filename: src/lib.rs</span> |
13cf67c4 | 345 | |
5869c6ff | 346 | ```rust,noplayground |
923072b8 | 347 | {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-15/src/lib.rs}} |
13cf67c4 XL |
348 | ``` |
349 | ||
923072b8 | 350 | <span class="caption">Listing 10-15: Conditionally implementing methods on a |
13cf67c4 XL |
351 | generic type depending on trait bounds</span> |
352 | ||
353 | We can also conditionally implement a trait for any type that implements | |
354 | another trait. Implementations of a trait on any type that satisfies the trait | |
355 | bounds are called *blanket implementations* and are extensively used in the | |
356 | Rust standard library. For example, the standard library implements the | |
357 | `ToString` trait on any type that implements the `Display` trait. The `impl` | |
358 | block in the standard library looks similar to this code: | |
359 | ||
360 | ```rust,ignore | |
361 | impl<T: Display> ToString for T { | |
362 | // --snip-- | |
363 | } | |
364 | ``` | |
365 | ||
366 | Because the standard library has this blanket implementation, we can call the | |
367 | `to_string` method defined by the `ToString` trait on any type that implements | |
368 | the `Display` trait. For example, we can turn integers into their corresponding | |
369 | `String` values like this because integers implement `Display`: | |
370 | ||
371 | ```rust | |
372 | let s = 3.to_string(); | |
373 | ``` | |
374 | ||
375 | Blanket implementations appear in the documentation for the trait in the | |
376 | “Implementors” section. | |
377 | ||
378 | Traits and trait bounds let us write code that uses generic type parameters to | |
379 | reduce duplication but also specify to the compiler that we want the generic | |
380 | type to have particular behavior. The compiler can then use the trait bound | |
381 | information to check that all the concrete types used with our code provide the | |
382 | correct behavior. In dynamically typed languages, we would get an error at | |
ba9703b0 XL |
383 | runtime if we called a method on a type which didn’t define the method. But Rust |
384 | moves these errors to compile time so we’re forced to fix the problems before | |
385 | our code is even able to run. Additionally, we don’t have to write code that | |
386 | checks for behavior at runtime because we’ve already checked at compile time. | |
387 | Doing so improves performance without having to give up the flexibility of | |
388 | generics. | |
13cf67c4 | 389 | |
5e7ed085 | 390 | [using-trait-objects-that-allow-for-values-of-different-types]: ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types |
3c0e092e | 391 | [methods]: ch05-03-method-syntax.html#defining-methods |