mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-03-20 14:31:15 +02:00
Be clear that the methods-and-traits exercise does not require generics (#2568)
When teaching the course, I got a little tripped up thinking students would need to make the `VerbosityFilter` generic over `Logger`. Let's be clearer that this is not required, and will be described later. This also updates the generic-types slide to repeat the exercise, completing that thought.
This commit is contained in:
parent
15e46379b1
commit
b3c57e4cbf
@ -4,46 +4,54 @@ minutes: 10
|
||||
|
||||
# Generic Data Types
|
||||
|
||||
You can use generics to abstract over the concrete field type:
|
||||
You can use generics to abstract over the concrete field type. Returning to the
|
||||
exercise for the previous segment:
|
||||
|
||||
```rust,editable
|
||||
#[derive(Debug)]
|
||||
struct Point<T> {
|
||||
x: T,
|
||||
y: T,
|
||||
pub trait Logger {
|
||||
/// Log a message at the given verbosity level.
|
||||
fn log(&self, verbosity: u8, message: &str);
|
||||
}
|
||||
|
||||
impl<T> Point<T> {
|
||||
fn coords(&self) -> (&T, &T) {
|
||||
(&self.x, &self.y)
|
||||
}
|
||||
struct StderrLogger;
|
||||
|
||||
fn set_x(&mut self, x: T) {
|
||||
self.x = x;
|
||||
impl Logger for StderrLogger {
|
||||
fn log(&self, verbosity: u8, message: &str) {
|
||||
eprintln!("verbosity={verbosity}: {message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Only log messages up to the given verbosity level.
|
||||
struct VerbosityFilter<L: Logger> {
|
||||
max_verbosity: u8,
|
||||
inner: L,
|
||||
}
|
||||
|
||||
impl<L: Logger> Logger for VerbosityFilter<L> {
|
||||
fn log(&self, verbosity: u8, message: &str) {
|
||||
if verbosity <= self.max_verbosity {
|
||||
self.inner.log(verbosity, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let integer = Point { x: 5, y: 10 };
|
||||
let float = Point { x: 1.0, y: 4.0 };
|
||||
println!("{integer:?} and {float:?}");
|
||||
println!("coords: {:?}", integer.coords());
|
||||
let logger = VerbosityFilter { max_verbosity: 3, inner: StderrLogger };
|
||||
logger.log(5, "FYI");
|
||||
logger.log(2, "Uhoh");
|
||||
}
|
||||
```
|
||||
|
||||
<details>
|
||||
|
||||
- _Q:_ Why `T` is specified twice in `impl<T> Point<T> {}`? Isn't that
|
||||
redundant?
|
||||
- _Q:_ Why `L` is specified twice in `impl<L: Logger> .. VerbosityFilter<L>`?
|
||||
Isn't that redundant?
|
||||
- This is because it is a generic implementation section for generic type.
|
||||
They are independently generic.
|
||||
- It means these methods are defined for any `T`.
|
||||
- It is possible to write `impl Point<u32> { .. }`.
|
||||
- `Point` is still generic and you can use `Point<f64>`, but methods in this
|
||||
block will only be available for `Point<u32>`.
|
||||
|
||||
- Try declaring a new variable `let p = Point { x: 5, y: 10.0 };`. Update the
|
||||
code to allow points that have elements of different types, by using two type
|
||||
variables, e.g., `T` and `U`.
|
||||
- It means these methods are defined for any `L`.
|
||||
- It is possible to write `impl VerbosityFilter<StderrLogger> { .. }`.
|
||||
- `VerbosityFilter` is still generic and you can use `VerbosityFilter<f64>`,
|
||||
but methods in this block will only be available for
|
||||
`Point<StderrLogger>`.
|
||||
|
||||
</details>
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
minutes: 20
|
||||
minutes: 15
|
||||
---
|
||||
|
||||
# Exercise: Logger Trait
|
||||
@ -14,13 +14,14 @@ verbosity. Your task is to write a `VerbosityFilter` type that will ignore
|
||||
messages above a maximum verbosity.
|
||||
|
||||
This is a common pattern: a struct wrapping a trait implementation and
|
||||
implementing that same trait, adding behavior in the process. What other kinds
|
||||
of wrappers might be useful in a logging utility?
|
||||
implementing that same trait, adding behavior in the process. In the "Generics"
|
||||
segment this afternoon, we will see how to make the wrapper generic over the
|
||||
wrapped type.
|
||||
|
||||
```rust,compile_fail
|
||||
{{#include exercise.rs:setup}}
|
||||
|
||||
// TODO: Define and implement `VerbosityFilter`.
|
||||
// TODO: Implement the `Logger` trait for `VerbosityFilter`.
|
||||
|
||||
{{#include exercise.rs:main}}
|
||||
```
|
||||
|
@ -26,13 +26,13 @@ impl Logger for StderrLogger {
|
||||
eprintln!("verbosity={verbosity}: {message}");
|
||||
}
|
||||
}
|
||||
// ANCHOR_END: setup
|
||||
|
||||
/// Only log messages up to the given verbosity level.
|
||||
struct VerbosityFilter {
|
||||
max_verbosity: u8,
|
||||
inner: StderrLogger,
|
||||
}
|
||||
// ANCHOR_END: setup
|
||||
|
||||
impl Logger for VerbosityFilter {
|
||||
fn log(&self, verbosity: u8, message: &str) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user