From 0e92165eafee26e0fb27f9a3756e8a68884d685d Mon Sep 17 00:00:00 2001 From: Leif Arne Storset Date: Sun, 19 Jul 2015 13:22:39 +0200 Subject: [PATCH] Show impl This includes a new example with Rectangle, instead of reusing HasArea, because fn area would require the Mul trait, and the added complexity of that would be better left for the Operators and Overloading chapter. Squashed at reviewer's request: Move teaser for trait bounds to bottom --- src/doc/trpl/generics.md | 30 +++++++++++++++++++---- src/doc/trpl/traits.md | 51 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/src/doc/trpl/generics.md b/src/doc/trpl/generics.md index c28d7c71608b..a8fdec805de6 100644 --- a/src/doc/trpl/generics.md +++ b/src/doc/trpl/generics.md @@ -101,11 +101,6 @@ fn takes_two_things(x: T, y: U) { } ``` -Generic functions are most useful with ‘trait bounds’, which we’ll cover in the -[section on traits][traits]. - -[traits]: traits.html - ## Generic structs You can store a generic type in a `struct` as well: @@ -122,3 +117,28 @@ let float_origin = Point { x: 0.0, y: 0.0 }; Similarly to functions, the `` is where we declare the generic parameters, and we then use `x: T` in the type declaration, too. + +When you want to add an implementation for the generic struct, you just +declare the type parameter after the `impl`: + +```rust +# struct Point { +# x: T, +# y: T, +# } +# +impl Point { + fn swap(&mut self) { + std::mem::swap(&mut self.x, &mut self.y); + } +} +``` + +So far you’ve seen generics that take absolutely any type. These are useful in +many cases: you’ve already seen `Option`, and later you’ll meet universal +container types like [`Vec`][Vec]. On the other hand, often you want to +trade that flexibility for increased expressive power. Read about [trait +bounds][traits] to see why and how. + +[traits]: traits.html +[Vec]: ../std/vec/struct.Vec.html diff --git a/src/doc/trpl/traits.md b/src/doc/trpl/traits.md index 687e2bbf00e7..e7542756d52e 100644 --- a/src/doc/trpl/traits.md +++ b/src/doc/trpl/traits.md @@ -152,6 +152,57 @@ We get a compile-time error: error: the trait `HasArea` is not implemented for the type `_` [E0277] ``` +## Traits bounds for generic structs + +Trait constraints also can apply to implementations for generic structs. Just +append the constraint when you declare type parameters. Here is a new type +type `Rectangle` and its operation `is_square()`: + +```rust +struct Rectangle { + x: T, + y: T, + width: T, + height: T, +} + +impl Rectangle { + fn is_square(&self) -> bool { + self.width == self.height + } +} + +fn main() { + let mut r = Rectangle { + x: 0, + y: 0, + width: 47, + height: 47, + }; + + assert!(r.is_square()); + + r.height = 42; + assert!(!r.is_square()); +} +``` + +`is_square()` needs to check that the sides are equal, so the sides must be of +a type that implements the [`core::cmp::PartialEq`][PartialEq] trait: + +```ignore +impl Rectangle { ... } +``` + +Now, a rectangle can be defined in terms of any type that can be compared for +equality. + +[PartialEq]: ../core/cmp/trait.PartialEq.html + + + +# Rules for implementing traits + So far, we’ve only added trait implementations to structs, but you can implement a trait for any type. So technically, we _could_ implement `HasArea` for `i32`: