1
0
mirror of https://github.com/google/comprehensive-rust.git synced 2025-01-07 08:45:24 +02:00

Cover Supertraits, Generic Traits (#1854)

This commit is contained in:
Dustin J. Mitchell 2024-03-12 09:49:39 -04:00 committed by GitHub
parent d0656ca90b
commit ac2cb44d54
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 97 additions and 2 deletions

View File

@ -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)

View File

@ -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<u32> for Foo {
fn from(from: u32) -> Foo {
Foo(format!("Converted from integer: {from}"))
}
}
impl From<bool> 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:?}");
}
```
<details>
- 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).
</details>

View File

@ -1,5 +1,5 @@
---
minutes: 10
minutes: 15
---
# Traits

View File

@ -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

View File

@ -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());
}
```
<details>
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.
<details>