Build the mental model
`Vec<T>` is the opposite of Lesson 4's fixed-size array — a growable, heap-allocated list whose size can change at runtime — `push`/`pop` add and remove elements, and every element must share the same type. `HashMap<K, V>` stores key-value pairs with average-case O(1) lookup via a hash function — the key type must implement the `Hash` trait (String and integers already implement it by default). Pushing or inserting a value into a `Vec`/`HashMap` moves that value's ownership into the collection, exactly following Lesson 6's ownership rules — trying to keep using the original variable afterward is a compile error, so you have to choose the tradeoff between `.clone()` (deep-copying, giving the collection its own copy) or a borrow-based design (storing references, at the cost of more lifetime management). `HashMap`'s `entry` API (`map.entry(key).or_insert(0)`) lets you check for a key and insert a default value in one line, which is extremely useful for use cases like word-frequency counting. Collections are almost always iterated by reference (`for item in &vec`), following Lesson 7's borrowing pattern, since you usually want a read-only traversal rather than consuming (taking ownership of) the collection.
Connect it to a real scenario
Accumulate the content analyzer's lesson stats starting with `let mut all_stats: Vec<LessonStat> = Vec::new();`, and inside the directory-scanning loop, `all_stats.push(stat);` — each push moves ownership into the vector, so the loop variable can't be reused after that push. To count tag frequency, use a `HashMap<String, u32>` with `*tag_counts.entry(tag.clone()).or_insert(0) += 1;` — the `entry` API handles both "key already exists" and "insert a new one" in one line. For the final report, iterate by reference with `for stat in &all_stats { ... }`, since `all_stats` may need to be used again after this reporting loop, so ownership shouldn't be taken.
Try the working example
use std::collections::HashMap;
fn main() {
let mut all_titles: Vec<String> = Vec::new();
all_titles.push(String::from("Ownership"));
all_titles.push(String::from("Borrowing"));
let mut tag_counts: HashMap<String, u32> = HashMap::new();
for tag in ["rust", "ownership", "rust", "borrowing", "rust"] {
*tag_counts.entry(tag.to_string()).or_insert(0) += 1;
}
println!("{all_titles:?}");
println!("rust seen {} times", tag_counts["rust"]);
}You print `["Ownership", "Borrowing"]` and "rust seen 3 times".5-minute try-it
Build a `HashMap<String, u32>` word-frequency counter from an array of string slices (words) using the `entry` API — sort and print the results from most to least frequent.
One important caution
Pushing a `String` variable into a `Vec` inside a loop and then trying to reuse that variable — ownership has moved, producing a "value borrowed after move" compile error; clone it if you need it again.
Accessing a `HashMap` directly with `map[key]` without checking whether the key exists — a missing key causes a runtime panic; `.get(key)` (returning an Option) is safer.