# Solution

```rust,editable
{{#include exercise.rs:solution}}
```

- **Storing Closures:** To store a closure in a struct, we use a generic type
  parameter (here `P`). This is because every closure in Rust has a unique,
  anonymous type generated by the compiler.
- **`Fn` Trait Bound:** The bound `P: Fn(u8, &str) -> bool` tells the compiler
  that `P` can be called as a function with the specified arguments and return
  type. We use `Fn` (instead of `FnMut` or `FnOnce`) because `log` takes
  `&self`, so we can only access the predicate immutably.
- **Calling fields:** We invoke the closure using `(self.predicate)(...)`. The
  parentheses around `self.predicate` are necessary to disambiguate between
  calling a method named `predicate` and calling the field itself.

<details>

- Discuss why `Fn` is required. If we used `FnMut`, `log` would need to take
  `&mut self`, which conflicts with the `Logger` trait signature. If we used
  `FnOnce`, we could only log a single message!
- The `impl` block for `new` also includes the bounds. While technically not
  strictly required for the struct definition itself (bounds can be placed only
  on `impl` blocks that use them), putting them on `new` helps type inference.

</details>
