diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 690f81e3..0f34eceb 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -82,6 +82,7 @@ - [Methods](methods-and-traits/methods.md) - [Traits](methods-and-traits/traits.md) - [Implmementing Traits](methods-and-traits/traits/implementing.md) + - [Supertraits](methods-and-traits/traits/supertraits.md) - [Associated Types](methods-and-traits/traits/associated-types.md) - [Deriving](methods-and-traits/deriving.md) - [Exercise: Generic Logger](methods-and-traits/exercise.md) @@ -89,6 +90,7 @@ - [Generics](generics.md) - [Generic Functions](generics/generic-functions.md) - [Generic Data Types](generics/generic-data.md) + - [Generic Traits](generics/generic-traits.md) - [Trait Bounds](generics/trait-bounds.md) - [`impl Trait`](generics/impl-trait.md) - [Exercise: Generic `min`](generics/exercise.md) diff --git a/src/generics/generic-traits.md b/src/generics/generic-traits.md new file mode 100644 index 00000000..cd14a961 --- /dev/null +++ b/src/generics/generic-traits.md @@ -0,0 +1,52 @@ +--- +Minutes: 5 +--- + +# Generic Traits + +Traits can also be generic, just like types and functions. A trait's parameters +get concrete types when it is used. + +```rust,editable +#[derive(Debug)] +struct Foo(String); + +impl From for Foo { + fn from(from: u32) -> Foo { + Foo(format!("Converted from integer: {from}")) + } +} + +impl From for Foo { + fn from(from: bool) -> Foo { + Foo(format!("Converted from bool: {from}")) + } +} + +fn main() { + let from_int = Foo::from(123); + let from_bool = Foo::from(true); + println!("{from_int:?}, {from_bool:?}"); +} +``` + +
+ +- The `From` trait will be covered later in the course, but its + [definition in the `std` docs](https://doc.rust-lang.org/std/convert/trait.From.html) + is simple. + +- Implementations of the trait do not need to cover all possible type + parameters. Here, `Foo::From("hello")` would not compile because there is no + `From<&str>` implementation for `Foo`. + +- Generic traits take types as "input", while associated types are a kind of + "output type. A trait can have multiple implementations for different input + types. + +- In fact, Rust requires that at most one implementation of a trait match for + any type T. Unlike some other languages, Rust has no heuristic for choosing + the "most specific" match. There is work on adding this support, called + [specialization](https://rust-lang.github.io/rfcs/1210-impl-specialization.html). + +
diff --git a/src/methods-and-traits/traits.md b/src/methods-and-traits/traits.md index 40c6517b..d6976e1f 100644 --- a/src/methods-and-traits/traits.md +++ b/src/methods-and-traits/traits.md @@ -1,5 +1,5 @@ --- -minutes: 10 +minutes: 15 --- # Traits diff --git a/src/methods-and-traits/traits/associated-types.md b/src/methods-and-traits/traits/associated-types.md index fc2a575e..beb00e78 100644 --- a/src/methods-and-traits/traits/associated-types.md +++ b/src/methods-and-traits/traits/associated-types.md @@ -1,6 +1,6 @@ # Associated Types -Associated types are placeholder types which are filled in by the trait +Associated types are placeholder types which are supplied by the trait implementation. ```rust,editable diff --git a/src/methods-and-traits/traits/supertraits.md b/src/methods-and-traits/traits/supertraits.md new file mode 100644 index 00000000..a06794c3 --- /dev/null +++ b/src/methods-and-traits/traits/supertraits.md @@ -0,0 +1,41 @@ +# Supertraits + +A trait can require that types implementing it also implement other traits, +called _supertraits_. Here, any type implementing `Pet` must implement `Animal`. + +```rust,editable +trait Animal { + fn leg_count(&self) -> u32; +} + +trait Pet: Animal { + fn name(&self) -> String; +} + +struct Dog(String); + +impl Animal for Dog { + fn leg_count(&self) -> u32 { + 4 + } +} + +impl Pet for Dog { + fn name(&self) -> String { + self.0.clone() + } +} + +fn main() { + let puppy = Dog(String::from("Rex")); + println!("{} has {} legs", puppy.name(), puppy.leg_count()); +} +``` + +
+ +This is sometimes called "trait inheritance" but students should not expect this +to behave like OO inheritance. It just specifies an additional requirement on +implementations of a trait. + +