diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 0f1107bc..a0337da6 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -80,6 +80,8 @@ - [Methods and Traits](methods-and-traits.md) - [Methods](methods-and-traits/methods.md) - [Traits](methods-and-traits/traits.md) + - [Implmementing Traits](methods-and-traits/traits/implementing.md) + - [Associated Types](methods-and-traits/traits/associated-types.md) - [Deriving](methods-and-traits/deriving.md) - [Exercise: Generic Logger](methods-and-traits/exercise.md) - [Solution](methods-and-traits/solution.md) diff --git a/src/methods-and-traits/traits.md b/src/methods-and-traits/traits.md index 1a5924d9..40c6517b 100644 --- a/src/methods-and-traits/traits.md +++ b/src/methods-and-traits/traits.md @@ -1,5 +1,5 @@ --- -minutes: 8 +minutes: 10 --- # Traits @@ -7,40 +7,12 @@ minutes: 8 Rust lets you abstract over types with traits. They're similar to interfaces: ```rust,editable -struct Dog { - name: String, - age: i8, -} -struct Cat { - lives: i8, -} - trait Pet { + /// Return a sentence from this pet. fn talk(&self) -> String; - fn greet(&self) { - println!("Oh you're a cutie! What's your name? {}", self.talk()); - } -} - -impl Pet for Dog { - fn talk(&self) -> String { - format!("Woof, my name is {}!", self.name) - } -} - -impl Pet for Cat { - fn talk(&self) -> String { - String::from("Miau!") - } -} - -fn main() { - let captain_floof = Cat { lives: 9 }; - let fido = Dog { name: String::from("Fido"), age: 5 }; - - captain_floof.greet(); - fido.greet(); + /// Print a string to the terminal greeting this pet. + fn greet(&self); } ``` @@ -49,10 +21,7 @@ fn main() { - A trait defines a number of methods that types must have in order to implement the trait. -- Traits are implemented in an `impl for { .. }` block. - -- Traits may specify pre-implemented (provided) methods and methods that users - are required to implement themselves. Provided methods can rely on required - methods. In this case, `greet` is provided, and relies on `talk`. +- In the "Generics" segment, next, we will see how to build functionality that + is generic over all types implementing a trait. diff --git a/src/methods-and-traits/traits/associated-types.md b/src/methods-and-traits/traits/associated-types.md new file mode 100644 index 00000000..a49ec5e9 --- /dev/null +++ b/src/methods-and-traits/traits/associated-types.md @@ -0,0 +1,37 @@ +# Associated Types + +Associated types allow are placeholder types which are filled in by the trait +implementation. + +```rust,editable +#[derive(Debug)] +struct Meters(i32); +#[derive(Debug)] +struct MetersSquared(i32); + +trait Multiply { + type Output; + fn multiply(&self, other: &Self) -> Self::Output; +} + +impl Multiply for Meters { + type Output = MetersSquared; + fn multiply(&self, other: &Self) -> Self::Output { + MetersSquared(self.0 * other.0) + } +} + +fn main() { + println!("{:?}", Meters(10).multiply(&Meters(20))); +} +``` + +
+ +- Associated types are sometimes also called "output types". The key observation + is that the implementer, not the caller, chooses this type. + +- Many standard library traits have associated types, including arithmetic + operators and `Iterator`. + +
diff --git a/src/methods-and-traits/traits/implementing.md b/src/methods-and-traits/traits/implementing.md new file mode 100644 index 00000000..f0081da1 --- /dev/null +++ b/src/methods-and-traits/traits/implementing.md @@ -0,0 +1,42 @@ +# Implementing Traits + +```rust,editable +trait Pet { + fn talk(&self) -> String; + + fn greet(&self) { + println!("Oh you're a cutie! What's your name? {}", self.talk()); + } +} + +struct Dog { + name: String, + age: i8, +} + +impl Pet for Dog { + fn talk(&self) -> String { + format!("Woof, my name is {}!", self.name) + } +} + +fn main() { + let fido = Dog { name: String::from("Fido"), age: 5 }; + fido.greet(); +} +``` + +
+ +- To implement `Trait` for `Type`, you use an `impl Trait for Type { .. }` + block. + +- Unlike Go interfaces, just having matching methods is not enough: a `Cat` type + with a `talk()` method would not automatically satisfy `Pet` unless it is in + an `impl Pet` block. + +- Traits may provide default implementations of some methods. Default + implementations can rely on all the methods of the trait. In this case, + `greet` is provided, and relies on `talk`. + +