diff --git a/src/control-flow-basics/break-continue/labels.md b/src/control-flow-basics/break-continue/labels.md
index bff046fe..55e26ae6 100644
--- a/src/control-flow-basics/break-continue/labels.md
+++ b/src/control-flow-basics/break-continue/labels.md
@@ -19,3 +19,15 @@ fn main() {
     print!("elements searched: {elements_searched}");
 }
 ```
+
+<details>
+
+- Labeled break also works on arbitrary blocks, e.g.
+  ```rust
+  'label: {
+      break 'label;
+      println!("This line gets skipped");
+  }
+  ```
+
+</details>
diff --git a/src/control-flow-basics/exercise.md b/src/control-flow-basics/exercise.md
index 6f7df66d..45d0e32a 100644
--- a/src/control-flow-basics/exercise.md
+++ b/src/control-flow-basics/exercise.md
@@ -30,7 +30,7 @@ initial `n`.
   todo!("Implement this")
 }
 
+{{#include exercise.rs:tests}}
+
 {{#include exercise.rs:main}}
-  todo!("Implement this")
-}
 ```
diff --git a/src/control-flow-basics/exercise.rs b/src/control-flow-basics/exercise.rs
index 2ebc2e1e..4cb79df3 100644
--- a/src/control-flow-basics/exercise.rs
+++ b/src/control-flow-basics/exercise.rs
@@ -34,6 +34,6 @@ fn test_collatz_length() {
 
 // ANCHOR: main
 fn main() {
-    // ANCHOR_END: main
     println!("Length: {}", collatz_length(11));
 }
+// ANCHOR_END: main
diff --git a/src/generics/generic-functions.md b/src/generics/generic-functions.md
index 4c2a3192..6e0b56b3 100644
--- a/src/generics/generic-functions.md
+++ b/src/generics/generic-functions.md
@@ -19,7 +19,7 @@ fn pick<T>(n: i32, even: T, odd: T) -> T {
 
 fn main() {
     println!("picked a number: {:?}", pick(97, 222, 333));
-    println!("picked a tuple: {:?}", pick(28, ("dog", 1), ("cat", 2)));
+    println!("picked a string: {:?}", pick(28, "dog", "cat"));
 }
 ```
 
@@ -27,6 +27,17 @@ fn main() {
 
 - Rust infers a type for T based on the types of the arguments and return value.
 
+- In this example we only use the primitive types `i32` and `&str` for `T`, but
+  we can use any type here, including user-defined types:
+
+  ```rust,ignore
+  struct Foo {
+      val: u8,
+  }
+
+  pick(123, Foo { val: 7 }, Foo { val: 456 });
+  ```
+
 - This is similar to C++ templates, but Rust partially compiles the generic
   function immediately, so that function must be valid for all types matching
   the constraints. For example, try modifying `pick` to return `even + odd` if
diff --git a/src/methods-and-traits/exercise.rs b/src/methods-and-traits/exercise.rs
index d9c66086..f7b9fa03 100644
--- a/src/methods-and-traits/exercise.rs
+++ b/src/methods-and-traits/exercise.rs
@@ -14,25 +14,18 @@
 
 // ANCHOR: solution
 // ANCHOR: setup
-use std::fmt::Display;
-
 pub trait Logger {
     /// Log a message at the given verbosity level.
-    fn log(&self, verbosity: u8, message: impl Display);
+    fn log(&self, verbosity: u8, message: &str);
 }
 
 struct StderrLogger;
 
 impl Logger for StderrLogger {
-    fn log(&self, verbosity: u8, message: impl Display) {
+    fn log(&self, verbosity: u8, message: &str) {
         eprintln!("verbosity={verbosity}: {message}");
     }
 }
-
-fn do_things(logger: &impl Logger) {
-    logger.log(5, "FYI");
-    logger.log(2, "Uhoh");
-}
 // ANCHOR_END: setup
 
 /// Only log messages up to the given verbosity level.
@@ -42,7 +35,7 @@ struct VerbosityFilter {
 }
 
 impl Logger for VerbosityFilter {
-    fn log(&self, verbosity: u8, message: impl Display) {
+    fn log(&self, verbosity: u8, message: &str) {
         if verbosity <= self.max_verbosity {
             self.inner.log(verbosity, message);
         }
@@ -51,7 +44,8 @@ impl Logger for VerbosityFilter {
 
 // ANCHOR: main
 fn main() {
-    let l = VerbosityFilter { max_verbosity: 3, inner: StderrLogger };
-    do_things(&l);
+    let logger = VerbosityFilter { max_verbosity: 3, inner: StderrLogger };
+    logger.log(5, "FYI");
+    logger.log(2, "Uhoh");
 }
 // ANCHOR_END: main
diff --git a/src/pattern-matching/destructuring-enums.md b/src/pattern-matching/destructuring-enums.md
index cb82b006..f9e30c42 100644
--- a/src/pattern-matching/destructuring-enums.md
+++ b/src/pattern-matching/destructuring-enums.md
@@ -47,12 +47,5 @@ arm, `half` is bound to the value inside the `Ok` variant. In the second arm,
   matched.
 - Demonstrate what happens when the search is inexhaustive. Note the advantage
   the Rust compiler provides by confirming when all cases are handled.
-- Save the result of `divide_in_two` in the `result` variable and `match` it in
-  a loop. That won't compile because `msg` is consumed when matched. To fix it,
-  match `&result` instead of `result`. That will make `msg` a reference so it
-  won't be consumed. This
-  ["match ergonomics"](https://rust-lang.github.io/rfcs/2005-match-ergonomics.html)
-  appeared in Rust 2018. If you want to support older Rust, replace `msg` with
-  `ref msg` in the pattern.
 
 </details>
diff --git a/src/pattern-matching/exercise.rs b/src/pattern-matching/exercise.rs
index 84a51631..1dfb3f49 100644
--- a/src/pattern-matching/exercise.rs
+++ b/src/pattern-matching/exercise.rs
@@ -44,11 +44,11 @@ fn eval(e: Expression) -> Result<i64, String> {
         Expression::Op { op, left, right } => {
             let left = match eval(*left) {
                 Ok(v) => v,
-                e @ Err(_) => return e,
+                Err(e) => return Err(e),
             };
             let right = match eval(*right) {
                 Ok(v) => v,
-                e @ Err(_) => return e,
+                Err(e) => return Err(e),
             };
             Ok(match op {
                 Operation::Add => left + right,
diff --git a/src/pattern-matching/match.md b/src/pattern-matching/match.md
index fcd4a779..a8f75d94 100644
--- a/src/pattern-matching/match.md
+++ b/src/pattern-matching/match.md
@@ -56,4 +56,24 @@ Key Points:
 - The condition defined in the guard applies to every expression in a pattern
   with an `|`.
 
+# More To Explore
+
+- Another piece of pattern syntax you can show students is the `@` syntax which
+  binds a part of a pattern to a variable. For example:
+
+  ```rust
+  let opt = Some(123);
+  match opt {
+      outer @ Some(inner) => {
+          println!("outer: {outer:?}, inner: {inner}");
+      }
+      None => {}
+  }
+  ```
+
+  In this example `inner` has the value 123 which it pulled from the `Option`
+  via destructuring, `outer` captures the entire `Some(inner)` expression, so it
+  contains the full `Option::Some(123)`. This is rarely used but can be useful
+  in more complex patterns.
+
 </details>
diff --git a/src/references/shared.md b/src/references/shared.md
index a85497ff..2fa0c846 100644
--- a/src/references/shared.md
+++ b/src/references/shared.md
@@ -38,6 +38,8 @@ fn x_axis(x: &i32) -> &(i32, i32) {
 
 <details>
 
+- References can never be null in Rust, so null checking is not necessary.
+
 - A reference is said to "borrow" the value it refers to, and this is a good
   model for students not familiar with pointers: code can use the reference to
   access the value, but is still "owned" by the original variable. The course
diff --git a/src/references/slices.md b/src/references/slices.md
index 5f8855f9..825a1677 100644
--- a/src/references/slices.md
+++ b/src/references/slices.md
@@ -20,7 +20,6 @@ fn main() {
 ```
 
 - Slices borrow data from the sliced type.
-- Question: What happens if you modify `a[3]` right before printing `s`?
 
 <details>
 
@@ -43,10 +42,4 @@ fn main() {
 - Slices always borrow from another object. In this example, `a` has to remain
   'alive' (in scope) for at least as long as our slice.
 
-- The question about modifying `a[3]` can spark an interesting discussion, but
-  the answer is that for memory safety reasons you cannot do it through `a` at
-  this point in the execution, but you can read the data from both `a` and `s`
-  safely. It works before you created the slice, and again after the `println`,
-  when the slice is no longer used.
-
 </details>
diff --git a/src/std-types/hashmap.md b/src/std-types/hashmap.md
index 6399bc15..e611902c 100644
--- a/src/std-types/hashmap.md
+++ b/src/std-types/hashmap.md
@@ -67,11 +67,6 @@ fn main() {
 
 - Alternatively HashMap can be built from any `Iterator` which yields key-value
   tuples.
-- We are showing `HashMap<String, i32>`, and avoid using `&str` as key to make
-  examples easier. Using references in collections can, of course, be done, but
-  it can lead into complications with the borrow checker.
-  - Try removing `to_string()` from the example above and see if it still
-    compiles. Where do you think we might run into issues?
 
 - This type has several "method-specific" return types, such as
   `std::collections::hash_map::Keys`. These types often appear in searches of