Skip to content

Commit b3c57e4

Browse files
authored
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.
1 parent 15e4637 commit b3c57e4

File tree

3 files changed

+38
-29
lines changed

3 files changed

+38
-29
lines changed

src/generics/generic-data.md

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,46 +4,54 @@ minutes: 10
44

55
# Generic Data Types
66

7-
You can use generics to abstract over the concrete field type:
7+
You can use generics to abstract over the concrete field type. Returning to the
8+
exercise for the previous segment:
89

910
```rust,editable
10-
#[derive(Debug)]
11-
struct Point<T> {
12-
x: T,
13-
y: T,
11+
pub trait Logger {
12+
/// Log a message at the given verbosity level.
13+
fn log(&self, verbosity: u8, message: &str);
1414
}
1515
16-
impl<T> Point<T> {
17-
fn coords(&self) -> (&T, &T) {
18-
(&self.x, &self.y)
16+
struct StderrLogger;
17+
18+
impl Logger for StderrLogger {
19+
fn log(&self, verbosity: u8, message: &str) {
20+
eprintln!("verbosity={verbosity}: {message}");
1921
}
22+
}
23+
24+
/// Only log messages up to the given verbosity level.
25+
struct VerbosityFilter<L: Logger> {
26+
max_verbosity: u8,
27+
inner: L,
28+
}
2029
21-
fn set_x(&mut self, x: T) {
22-
self.x = x;
30+
impl<L: Logger> Logger for VerbosityFilter<L> {
31+
fn log(&self, verbosity: u8, message: &str) {
32+
if verbosity <= self.max_verbosity {
33+
self.inner.log(verbosity, message);
34+
}
2335
}
2436
}
2537
2638
fn main() {
27-
let integer = Point { x: 5, y: 10 };
28-
let float = Point { x: 1.0, y: 4.0 };
29-
println!("{integer:?} and {float:?}");
30-
println!("coords: {:?}", integer.coords());
39+
let logger = VerbosityFilter { max_verbosity: 3, inner: StderrLogger };
40+
logger.log(5, "FYI");
41+
logger.log(2, "Uhoh");
3142
}
3243
```
3344

3445
<details>
3546

36-
- _Q:_ Why `T` is specified twice in `impl<T> Point<T> {}`? Isn't that
37-
redundant?
47+
- _Q:_ Why `L` is specified twice in `impl<L: Logger> .. VerbosityFilter<L>`?
48+
Isn't that redundant?
3849
- This is because it is a generic implementation section for generic type.
3950
They are independently generic.
40-
- It means these methods are defined for any `T`.
41-
- It is possible to write `impl Point<u32> { .. }`.
42-
- `Point` is still generic and you can use `Point<f64>`, but methods in this
43-
block will only be available for `Point<u32>`.
44-
45-
- Try declaring a new variable `let p = Point { x: 5, y: 10.0 };`. Update the
46-
code to allow points that have elements of different types, by using two type
47-
variables, e.g., `T` and `U`.
51+
- It means these methods are defined for any `L`.
52+
- It is possible to write `impl VerbosityFilter<StderrLogger> { .. }`.
53+
- `VerbosityFilter` is still generic and you can use `VerbosityFilter<f64>`,
54+
but methods in this block will only be available for
55+
`Point<StderrLogger>`.
4856

4957
</details>

src/methods-and-traits/exercise.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
minutes: 20
2+
minutes: 15
33
---
44

55
# Exercise: Logger Trait
@@ -14,13 +14,14 @@ verbosity. Your task is to write a `VerbosityFilter` type that will ignore
1414
messages above a maximum verbosity.
1515

1616
This is a common pattern: a struct wrapping a trait implementation and
17-
implementing that same trait, adding behavior in the process. What other kinds
18-
of wrappers might be useful in a logging utility?
17+
implementing that same trait, adding behavior in the process. In the "Generics"
18+
segment this afternoon, we will see how to make the wrapper generic over the
19+
wrapped type.
1920

2021
```rust,compile_fail
2122
{{#include exercise.rs:setup}}
2223
23-
// TODO: Define and implement `VerbosityFilter`.
24+
// TODO: Implement the `Logger` trait for `VerbosityFilter`.
2425
2526
{{#include exercise.rs:main}}
2627
```

src/methods-and-traits/exercise.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ impl Logger for StderrLogger {
2626
eprintln!("verbosity={verbosity}: {message}");
2727
}
2828
}
29-
// ANCHOR_END: setup
3029

3130
/// Only log messages up to the given verbosity level.
3231
struct VerbosityFilter {
3332
max_verbosity: u8,
3433
inner: StderrLogger,
3534
}
35+
// ANCHOR_END: setup
3636

3737
impl Logger for VerbosityFilter {
3838
fn log(&self, verbosity: u8, message: &str) {

0 commit comments

Comments
 (0)