---
title: "18.1 Introduction to collections"
description: "What the standard collections are, why they live on the heap and can grow at runtime, and a map of Vec, String, and HashMap before diving in."
url: "https://learnrust.net/chapter-18/introduction-to-collections/"
last_updated: "2026-06-13"
---

# 18.1 Introduction to collections

Every program of any size needs to hold *many* values: a list of scores, the words in a file, a count of each item. The fixed, named fields of a struct (chapter 10) can't do that, because you don't know in advance how many there'll be. The standard library's **collections** can: they hold a variable number of values, growing and shrinking at runtime. This chapter covers the three you'll reach for constantly, `Vec`, `String`, and `HashMap`, and it's where ownership, borrowing, and generics all show up in code you'll write every day.

## Why collections live on the heap

Recall the stack-and-heap distinction from lesson [8.2](https://learnrust.net/chapter-8/the-stack-and-the-heap/). A value whose size is known at compile time can live in a stack frame; a value whose size changes at runtime cannot, because the frame is laid out when the function is compiled. A collection's whole point is that its size varies, you `push` onto it, it grows, so its contents live on the **heap**, with a small fixed-size handle on the stack pointing to them. This is exactly the anatomy of `String` from lesson [8.2](https://learnrust.net/chapter-8/the-stack-and-the-heap/): a stack handle (pointer, length, capacity) and heap-allocated contents. That wasn't a special `String` trick; it's how every growable collection works, and `String` was your first one.

Because they own heap data, collections follow the ownership rules you already know. A collection is dropped (and frees its heap memory) when its owner goes out of scope (lesson [8.3](https://learnrust.net/chapter-8/scope-and-drop/)); moving a collection moves its handle (lesson [8.4](https://learnrust.net/chapter-8/moves/)); and a collection is never `Copy` (lesson [8.5](https://learnrust.net/chapter-8/copy-types/)), because it owns heap memory. Everything from chapters 8 and 9 applies, which is why those chapters came first.

> **Key insight**
>
> A collection is an owning handle to a variable amount of heap data. That single sentence connects it to everything you know: it's heap-allocated because its size isn't fixed (chapter 8), it owns its contents so it drops and moves like any owner (chapter 8), you borrow it with `&` to read or `&mut` to modify (chapter 9), and it's generic over what it holds (chapter 15, `Vec<T>`, `HashMap<K, V>`). Collections are where the whole course so far becomes daily, practical tooling.

## The three core collections

This chapter focuses on three, because they cover the vast majority of real needs:

**`Vec<T>`** ("vector") is a growable list of values of the same type `T`, stored contiguously. It's the workhorse: whenever you want "a sequence of things" and the count varies, you reach for `Vec`. Lessons [18.2](https://learnrust.net/chapter-18/vec-creating-and-updating/) through [18.4](https://learnrust.net/chapter-18/vec-capacity-and-growth/) cover it.

**`String`** is a growable, UTF-8 text buffer, a `Vec` of bytes specialized for text. You've used it since chapter 1, but lesson [18.5](https://learnrust.net/chapter-18/string-as-a-collection/) finally examines it *as a collection*: why `s[0]` doesn't compile, what `chars()` versus `bytes()` give you, and why slicing can panic. This is the lesson that demystifies Rust strings for good.

**`HashMap<K, V>`** stores key-value pairs: look up a value by its key, like a dictionary. When you need "count how many times each word appears" or "find the score for this name," it's a `HashMap`. Lesson [18.6](https://learnrust.net/chapter-18/hashmap/) covers it.

After those, lesson [18.7](https://learnrust.net/chapter-18/arrays-and-slices-revisited/) revisits fixed-size arrays and slices in depth, and lesson [18.8](https://learnrust.net/chapter-18/choosing-a-collection/) is a decision guide to the rest of the standard collections (`VecDeque`, `HashSet`, `BTreeMap`) for when the core three aren't the right fit.

## Collection versus array

One distinction up front, since you've met fixed-size arrays in passing. An array `[i32; 5]` has a fixed length known at compile time and can live on the stack; a `Vec<i32>` has a length that varies at runtime and lives on the heap. Use an array when you know exactly how many elements there are and that never changes (the four bytes of an IP address, the seven days of a week); use a `Vec` when the count is dynamic, which is most of the time. Lesson [18.7](https://learnrust.net/chapter-18/arrays-and-slices-revisited/) draws the line in full; for now, "fixed count: array; varying count: `Vec`" is the rule.

## Quiz time

**Question #1**

Why do growable collections store their contents on the heap rather than the stack?

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

Because their size changes at runtime (you push and they grow), and a stack frame is laid out at compile time with fixed sizes (lesson [8.2](https://learnrust.net/chapter-8/the-stack-and-the-heap/)). A varying-size value can't fit in a fixed frame, so the contents live on the heap, with a small fixed-size handle on the stack pointing to them, exactly like `String`.

</details>

**Question #2**

A `Vec<String>` goes out of scope. What happens, and which chapter-8 rules are at work?

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

The `Vec` is dropped, which frees its heap buffer and drops each `String` it contains (freeing their heap text too), all automatically (lesson [8.3](https://learnrust.net/chapter-8/scope-and-drop/)). The `Vec` owns its contents, so cleanup nests all the way down. It also moves rather than copies (lesson [8.4](https://learnrust.net/chapter-8/moves/)) and is never `Copy` (lesson [8.5](https://learnrust.net/chapter-8/copy-types/)), because it owns heap memory.

</details>

**Question #3**

When would you use a fixed-size array instead of a `Vec`?

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

When the number of elements is known at compile time and never changes, like the 4 bytes of an IPv4 address or 7 days of the week. An array has a fixed length and can live on the stack; a `Vec` has a runtime-varying length on the heap. Fixed count: array; varying count: `Vec` (lesson [18.7](https://learnrust.net/chapter-18/arrays-and-slices-revisited/) covers the distinction fully).

</details>

The workhorse comes first. The next lesson creates and updates a `Vec`: the `vec!` macro, `push`, and the important difference between `get` (which returns `Option`) and `[]` indexing (which panics out of bounds).

## Sitemap

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