---
title: "15.x Chapter 15 summary and quiz"
description: "Review of the problem generics solve, generic functions, structs, enums, methods, and monomorphization, with a chapter quiz and an exercise."
url: "https://learnrust.net/chapter-15/chapter-15-summary-and-quiz/"
last_updated: "2026-06-13"
---

# 15.x Chapter 15 summary and quiz

This chapter removed duplication across types, and set up traits. Review, then a quiz.

## Quick review

Generics remove repetition across *types*, the way function parameters remove it across values ([15.1](https://learnrust.net/chapter-15/the-problem-generics-solve/)). A **type parameter** `<T>` is a placeholder a caller fills in, named by convention with a single uppercase letter. A generic function declares its parameters in angle brackets after the name and uses them in its signature ([15.2](https://learnrust.net/chapter-15/generic-functions/)). A generic body compiles without bounds only while it treats `T` as opaque (store, move, return); the moment it *uses* a capability (`>`, `==`, `+`, cloning, printing), the compiler demands a **trait bound** (chapter 16). The `largest` function is the standing example: it needs `T: PartialOrd`, and its E0369 error is literally chapter 16's table of contents. When inference can't pin down the type, the **turbofish** `::<T>` names it explicitly (as `parse::<i32>()` always did).

Structs and enums take type parameters too ([15.3](https://learnrust.net/chapter-15/generic-structs-and-enums/)), and the reveal is that `Option<T>`, `Result<T, E>`, and `Vec<T>` were generic all along, the `<T>` an ordinary type parameter. **Type aliases** (`type`) give a long generic type a short synonym (distinct from a newtype, which makes a new type), and **const generics** (`<const N: usize>`) range over compile-time values like array lengths. Methods on generic types use `impl<T> Type<T>` ([15.4](https://learnrust.net/chapter-15/generic-methods/)); writing a concrete `impl Type<f64>` instead gives a method to *only* that instantiation, the way `sqrt`-using methods exist only for `f64` points.

Finally, **monomorphization** ([15.5](https://learnrust.net/chapter-15/monomorphization/)): the compiler turns one generic definition into a specialized copy per type used, at compile time, so generics are **zero-cost** at runtime, as fast as hand-written concrete code. The price is paid in binary size and compile time, not runtime. When you need one shared copy across many types at runtime, trait objects (lesson [16.9](https://learnrust.net/chapter-16/trait-objects/)) are the alternative.

## Quiz time

**Question #1**

What's the parallel between a type parameter and an ordinary function parameter?

<details class="solution">
<summary>Show solution</summary>

A function parameter is a placeholder for a *value* the caller supplies, letting one function body serve many values of a fixed type. A type parameter `<T>` is a placeholder for a *type* the caller supplies, letting one definition serve many types. Generics are to types what parameters are to values.

</details>

**Question #2**

Does each of these compile as written? If not, why?

a)

```rust
fn identity<T>(x: T) -> T { x }
```

b)

```rust
fn show<T>(x: T) { println!("{x}"); }
```

c)

```rust
struct Wrap<T> { value: T }
```

<details class="solution">
<summary>Show solution</summary>

a) Compiles: it only returns the value, no capability needed. b) Does *not* compile: `println!("{x}")` needs `T` to be printable (the `Display` trait), so it requires a bound like `T: std::fmt::Display` (chapter 16). c) Compiles: a struct just *stores* a `T`; storing needs no bound.

</details>

**Question #3**

What does monomorphization do, and what does it cost?

<details class="solution">
<summary>Show solution</summary>

It generates a specialized copy of generic code for each concrete type used, at compile time, so the running program calls ordinary concrete functions with no runtime overhead (zero-cost). The cost is larger binary size (more copies) and longer compile time, both paid at build time, not at runtime.

</details>

**Question #4**

The exercise. Define a generic struct `Stack<T>` (a last-in-first-out stack) backed by a `Vec<T>`, with: `new()` returning an empty stack, `push(&mut self, item: T)`, `pop(&mut self) -> Option<T>`, and `len(&self) -> usize`. Then use it with `i32`s in `main`: push 1, 2, 3, pop one, and print the length. (You don't need any trait bounds for this.)

<details class="solution">
<summary>Show solution</summary>

```rust
struct Stack<T> {
    items: Vec<T>,
}

impl<T> Stack<T> {
    fn new() -> Stack<T> {
        Stack { items: Vec::new() }
    }

    fn push(&mut self, item: T) {
        self.items.push(item);
    }

    fn pop(&mut self) -> Option<T> {
        self.items.pop()
    }

    fn len(&self) -> usize {
        self.items.len()
    }
}

fn main() {
    let mut stack = Stack::new();
    stack.push(1);
    stack.push(2);
    stack.push(3);
    stack.pop();
    println!("length: {}", stack.len());
}
```

```
length: 2
```

Design notes. `Stack<T>` is generic over the element type and stores a `Vec<T>` (itself generic, lesson [15.3](https://learnrust.net/chapter-15/generic-structs-and-enums/)). `impl<T> Stack<T>` declares the parameter so the methods are available for every element type. `pop` returns `Option<T>` because the stack might be empty (lesson [11.3](https://learnrust.net/chapter-11/option/)), matching `Vec::pop`. No bounds are needed because the methods only store, move, and return `T`, never compare or print it. The compiler infers `Stack<i32>` from the `push(1)` calls; pushing a `String` instead would make a `Stack<String>` from the same definition. (`Vec` and its methods are chapter 18; here it's just the backing store.)

</details>

You can write code generic over types, but the body still can't *do* much with them. Chapter 16 lifts that ceiling: **traits** define shared behavior, **trait bounds** let a generic body compare, print, and compute with its type parameters, and `largest` finally compiles. It's the structural centerpiece of the language and the chapter where "Rust can be shorter than C++" is most dramatically true.

## Sitemap

See the full [sitemap](https://learnrust.net/sitemap.md) for all pages.
