Collections in Rust
# CHAPTER 14
Collections in Rust
1. Chapter Introduction
In Chapter 4, we learned about Arrays and Tuples. While useful, they are stored on the Stack, meaning their size is fixed at compile-time and cannot grow. Real-world data is unpredictable; you don't know how many users will sign up. Rust provides Collections, which store data on the Heap. This means they can grow and shrink dynamically. The three most commonly used collections are Vectors, Strings, and HashMaps.2. Learning Objectives
By the end of this chapter, you will be able to:-
Create, update, and iterate over Vectors (
Vec<T>).
-
Deeply understand how
Stringworks under the hood (UTF-8 bytes vs chars).
-
Create, insert, and safely retrieve data from a
HashMap.
3. Vectors (Vec<T>)
A Vector allows you to store more than one value in a single data structure that puts all the values next to each other in memory (like a dynamic array). Vectors can only store values of the *same type*.
Creating and Updating a Vector
Reading from a Vector
There are two ways to reference a value: via index, or via the .get() method.
4. Strings (The UTF-8 Complexity)
We used Strings earlier, but now we must confront a difficult truth: Strings in Rust are highly complex. AString is actually just a wrapper over a Vec<u8> (a vector of bytes) that guarantees the bytes represent valid UTF-8 text.
Because of UTF-8 (where an English letter takes 1 byte, but a Cyrillic letter takes 2 bytes, and an Emoji takes 4 bytes), Rust does NOT allow you to index into a String like an array (my_string[0]). Doing so could accidentally slice an emoji in half and crash the program!
Creating and Updating Strings
Iterating over Strings Safely
If you want to look at the individual human-readable characters, you must explicitly use the .chars() method.
5. HashMaps
A HashMap stores data in Key-Value pairs (similar to Objects in JS or Dictionaries in Python). They are incredibly fast for looking up data.You must bring it into scope using use std::collections::HashMap;.
Creating and Inserting Data
Retrieving Data
Because a key might not exist in the HashMap, .get() returns an Option<&V>.
6. Mini Project: Word Counter
Let's use a HashMap to count how many times each word appears in a string!7. Common Mistakes
-
Indexing Strings: Writing
let char = mystring[0];. Rust aggressively forbids this to prevent UTF-8 corruption.
-
HashMap Ownership: Inserting a
Stringinto a HashMap *moves* ownership of that string into the HashMap. The original variable becomes invalid. (Inserting primitives likei32just copies them).
8. Best Practices
-
Always use
.get()for Vectors: Unless you are mathematically certain the index exists, avoid&v[100]. Usev.get(100)and handle theNonecase to prevent server panics.
9. Exercises
- 1. Create a Vector of integers.
-
2.
Use a
forloop to iterate through the Vector, multiplying each number by 2, and print the results.
10. MCQs with Answers
Where are standard Collections (Vectors, Strings, HashMaps) stored in memory?
Which macro is the fastest way to create and initialize a Vector?
What is the danger of reading a Vector using indexing (e.g., &v[10])?
What does v.get(10) return to prevent crashing?
Fundamentally, what is a String in Rust?
mystring[0]?
a) Yes b) No, Rust prevents this because UTF-8 characters can vary in byte size
Answer: b) No, Rust prevents this to ensure UTF-8 safety.
How do you append a word to an existing mutable String?
Which Collection stores data in Key-Value pairs?
If you insert a String key into a HashMap, what happens to the original String variable?
What does the .orinsert() method do on a HashMap entry?
11. Interview Questions
- Q: Explain why Rust does not allow integer indexing into Strings. Give an example of how UTF-8 encoding justifies this design choice.
-
Q: Contrast the memory behavior of arrays
[i32; 5]vs VectorsVec<i32>.
12. FAQs
- Are HashMaps ordered? No. HashMaps do not preserve the order of insertion. If you iterate over a HashMap, the keys will print in a random order.
13. Summary
Collections empower your applications to handle dynamic data gracefully. Vectors provide standard list functionality, HashMaps offer lightning-fast key-value lookups, and Strings manage complex text data with uncompromising UTF-8 safety. Leveraging these tools, combined withOption handling via .get(), results in incredibly robust backend software.
14. Next Chapter Recommendation
We have used.expect() several times to crash the program when something goes wrong. In production, crashing is unacceptable. In Chapter 15: Error Handling in Rust, we will learn how to use the Result Enum to capture errors safely and recover from them gracefully.