]> git.lizzy.rs Git - rust.git/blob - src/doc/trpl/traits.md
TRPL: Add `rust` Marker to Some Code Block
[rust.git] / src / doc / trpl / traits.md
1 % Traits
2
3 Do you remember the `impl` keyword, used to call a function with [method
4 syntax][methodsyntax]?
5
6 ```rust
7 struct Circle {
8     x: f64,
9     y: f64,
10     radius: f64,
11 }
12
13 impl Circle {
14     fn area(&self) -> f64 {
15         std::f64::consts::PI * (self.radius * self.radius)
16     }
17 }
18 ```
19
20 [methodsyntax]: method-syntax.html
21
22 Traits are similar, except that we define a trait with just the method
23 signature, then implement the trait for that struct. Like this:
24
25 ```rust
26 struct Circle {
27     x: f64,
28     y: f64,
29     radius: f64,
30 }
31
32 trait HasArea {
33     fn area(&self) -> f64;
34 }
35
36 impl HasArea for Circle {
37     fn area(&self) -> f64 {
38         std::f64::consts::PI * (self.radius * self.radius)
39     }
40 }
41 ```
42
43 As you can see, the `trait` block looks very similar to the `impl` block,
44 but we don’t define a body, just a type signature. When we `impl` a trait,
45 we use `impl Trait for Item`, rather than just `impl Item`.
46
47 We can use traits to constrain our generics. Consider this function, which
48 does not compile, and gives us a similar error:
49
50 ```rust,ignore
51 fn print_area<T>(shape: T) {
52     println!("This shape has an area of {}", shape.area());
53 }
54 ```
55
56 Rust complains:
57
58 ```text
59 error: type `T` does not implement any method in scope named `area`
60 ```
61
62 Because `T` can be any type, we can’t be sure that it implements the `area`
63 method. But we can add a ‘trait constraint’ to our generic `T`, ensuring
64 that it does:
65
66 ```rust
67 # trait HasArea {
68 #     fn area(&self) -> f64;
69 # }
70 fn print_area<T: HasArea>(shape: T) {
71     println!("This shape has an area of {}", shape.area());
72 }
73 ```
74
75 The syntax `<T: HasArea>` means `any type that implements the HasArea trait`.
76 Because traits define function type signatures, we can be sure that any type
77 which implements `HasArea` will have an `.area()` method.
78
79 Here’s an extended example of how this works:
80
81 ```rust
82 trait HasArea {
83     fn area(&self) -> f64;
84 }
85
86 struct Circle {
87     x: f64,
88     y: f64,
89     radius: f64,
90 }
91
92 impl HasArea for Circle {
93     fn area(&self) -> f64 {
94         std::f64::consts::PI * (self.radius * self.radius)
95     }
96 }
97
98 struct Square {
99     x: f64,
100     y: f64,
101     side: f64,
102 }
103
104 impl HasArea for Square {
105     fn area(&self) -> f64 {
106         self.side * self.side
107     }
108 }
109
110 fn print_area<T: HasArea>(shape: T) {
111     println!("This shape has an area of {}", shape.area());
112 }
113
114 fn main() {
115     let c = Circle {
116         x: 0.0f64,
117         y: 0.0f64,
118         radius: 1.0f64,
119     };
120
121     let s = Square {
122         x: 0.0f64,
123         y: 0.0f64,
124         side: 1.0f64,
125     };
126
127     print_area(c);
128     print_area(s);
129 }
130 ```
131
132 This program outputs:
133
134 ```text
135 This shape has an area of 3.141593
136 This shape has an area of 1
137 ```
138
139 As you can see, `print_area` is now generic, but also ensures that we have
140 passed in the correct types. If we pass in an incorrect type:
141
142 ```rust,ignore
143 print_area(5);
144 ```
145
146 We get a compile-time error:
147
148 ```text
149 error: failed to find an implementation of trait main::HasArea for int
150 ```
151
152 So far, we’ve only added trait implementations to structs, but you can
153 implement a trait for any type. So technically, we _could_ implement `HasArea`
154 for `i32`:
155
156 ```rust
157 trait HasArea {
158     fn area(&self) -> f64;
159 }
160
161 impl HasArea for i32 {
162     fn area(&self) -> f64 {
163         println!("this is silly");
164
165         *self as f64
166     }
167 }
168
169 5.area();
170 ```
171
172 It is considered poor style to implement methods on such primitive types, even
173 though it is possible.
174
175 This may seem like the Wild West, but there are two other restrictions around
176 implementing traits that prevent this from getting out of hand. The first is
177 that if the trait isn’t defined in your scope, it doesn’t apply. Here’s an
178 example: the standard library provides a [`Write`][write] trait which adds
179 extra functionality to `File`s, for doing file I/O. By default, a `File`
180 won’t have its methods:
181
182 [write]: ../std/io/trait.Write.html
183
184 ```rust,ignore
185 let mut f = std::fs::File::open("foo.txt").ok().expect("Couldn’t open foo.txt");
186 let result = f.write("whatever".as_bytes());
187 # result.unwrap(); // ignore the error
188 ```
189
190 Here’s the error:
191
192 ```text
193 error: type `std::fs::File` does not implement any method in scope named `write`
194
195 let result = f.write(b"whatever");
196                ^~~~~~~~~~~~~~~~~~
197 ```
198
199 We need to `use` the `Write` trait first:
200
201 ```rust,ignore
202 use std::io::Write;
203
204 let mut f = std::fs::File::open("foo.txt").ok().expect("Couldn’t open foo.txt");
205 let result = f.write("whatever".as_bytes());
206 # result.unwrap(); // ignore the error
207 ```
208
209 This will compile without error.
210
211 This means that even if someone does something bad like add methods to `i32`,
212 it won’t affect you, unless you `use` that trait.
213
214 There’s one more restriction on implementing traits. Either the trait or the
215 type you’re writing the `impl` for must be defined by you. So, we could
216 implement the `HasArea` type for `i32`, because `HasArea` is in our code. But
217 if we tried to implement `Float`, a trait provided by Rust, for `i32`, we could
218 not, because neither the trait nor the type are in our code.
219
220 One last thing about traits: generic functions with a trait bound use
221 ‘monomorphization’ (mono: one, morph: form), so they are statically dispatched.
222 What’s that mean? Check out the chapter on [trait objects][to] for more details.
223
224 [to]: trait-objects.html
225
226 # Multiple trait bounds
227
228 You’ve seen that you can bound a generic type parameter with a trait:
229
230 ```rust
231 fn foo<T: Clone>(x: T) {
232     x.clone();
233 }
234 ```
235
236 If you need more than one bound, you can use `+`:
237
238 ```rust
239 use std::fmt::Debug;
240
241 fn foo<T: Clone + Debug>(x: T) {
242     x.clone();
243     println!("{:?}", x);
244 }
245 ```
246
247 `T` now needs to be both `Clone` as well as `Debug`.
248
249 # Where clause
250
251 Writing functions with only a few generic types and a small number of trait
252 bounds isn’t too bad, but as the number increases, the syntax gets increasingly
253 awkward:
254
255 ```rust
256 use std::fmt::Debug;
257
258 fn foo<T: Clone, K: Clone + Debug>(x: T, y: K) {
259     x.clone();
260     y.clone();
261     println!("{:?}", y);
262 }
263 ```
264
265 The name of the function is on the far left, and the parameter list is on the
266 far right. The bounds are getting in the way.
267
268 Rust has a solution, and it’s called a ‘`where` clause’:
269
270 ```rust
271 use std::fmt::Debug;
272
273 fn foo<T: Clone, K: Clone + Debug>(x: T, y: K) {
274     x.clone();
275     y.clone();
276     println!("{:?}", y);
277 }
278
279 fn bar<T, K>(x: T, y: K) where T: Clone, K: Clone + Debug {
280     x.clone();
281     y.clone();
282     println!("{:?}", y);
283 }
284
285 fn main() {
286     foo("Hello", "world");
287     bar("Hello", "workd");
288 }
289 ```
290
291 `foo()` uses the syntax we showed earlier, and `bar()` uses a `where` clause.
292 All you need to do is leave off the bounds when defining your type parameters,
293 and then add `where` after the parameter list. For longer lists, whitespace can
294 be added:
295
296 ```rust
297 use std::fmt::Debug;
298
299 fn bar<T, K>(x: T, y: K)
300     where T: Clone,
301           K: Clone + Debug {
302
303     x.clone();
304     y.clone();
305     println!("{:?}", y);
306 }
307 ```
308
309 This flexibility can add clarity in complex situations.
310
311 `where` is also more powerful than the simpler syntax. For example:
312
313 ```rust
314 trait ConvertTo<Output> {
315     fn convert(&self) -> Output;
316 }
317
318 impl ConvertTo<i64> for i32 {
319     fn convert(&self) -> i64 { *self as i64 }
320 }
321
322 // can be called with T == i32
323 fn normal<T: ConvertTo<i64>>(x: &T) -> i64 {
324     x.convert()
325 }
326
327 // can be called with T == i64
328 fn inverse<T>() -> T
329         // this is using ConvertTo as if it were "ConvertFrom<i32>"
330         where i32: ConvertTo<T> {
331     1i32.convert()
332 }
333 ```
334
335 This shows off the additional feature of `where` clauses: they allow bounds
336 where the left-hand side is an arbitrary type (`i32` in this case), not just a
337 plain type parameter (like `T`).
338
339 ## Default methods
340
341 There’s one last feature of traits we should cover: default methods. It’s
342 easiest just to show an example:
343
344 ```rust
345 trait Foo {
346     fn bar(&self);
347
348     fn baz(&self) { println!("We called baz."); }
349 }
350 ```
351
352 Implementors of the `Foo` trait need to implement `bar()`, but they don’t
353 need to implement `baz()`. They’ll get this default behavior. They can
354 override the default if they so choose:
355
356 ```rust
357 # trait Foo {
358 # fn bar(&self);
359 # fn baz(&self) { println!("We called baz."); }
360 # }
361 struct UseDefault;
362
363 impl Foo for UseDefault {
364     fn bar(&self) { println!("We called bar."); }
365 }
366
367 struct OverrideDefault;
368
369 impl Foo for OverrideDefault {
370     fn bar(&self) { println!("We called bar."); }
371
372     fn baz(&self) { println!("Override baz!"); }
373 }
374
375 let default = UseDefault;
376 default.baz(); // prints "We called baz."
377
378 let over = OverrideDefault;
379 over.baz(); // prints "Override baz!"
380 ```
381
382 # Inheritance
383
384 Sometimes, implementing a trait requires implementing another trait:
385
386 ```rust
387 trait Foo {
388     fn foo(&self);
389 }
390
391 trait FooBar : Foo {
392     fn foobar(&self);
393 }
394 ```
395
396 Implementors of `FooBar` must also implement `Foo`, like this:
397
398 ```rust
399 # trait Foo {
400 #     fn foo(&self);
401 # }
402 # trait FooBar : Foo {
403 #     fn foobar(&self);
404 # }
405 struct Baz;
406
407 impl Foo for Baz {
408     fn foo(&self) { println!("foo"); }
409 }
410
411 impl FooBar for Baz {
412     fn foobar(&self) { println!("foobar"); }
413 }
414 ```
415
416 If we forget to implement `Foo`, Rust will tell us:
417
418 ```text
419 error: the trait `main::Foo` is not implemented for the type `main::Baz` [E0277]
420 ```