18.1 Overview of Collections and Comparison with C

For developers coming from C, the most significant advantage of Rust’s collections is their automatic resource management. Instead of manually orchestrating malloc, realloc, and free, and meticulously tracking allocation sizes and capacities, you utilize Rust’s standard library types that handle these details internally.

Rust’s collections offer safety and convenience through:

  1. Automated Memory Management: Allocation and deallocation are handled automatically via Rust’s ownership system. When a collection variable goes out of scope, its destructor is called, freeing the associated heap memory and preventing leaks.
  2. Type Safety: Collections are generic (e.g., Vec<T>), ensuring they hold elements of only one specific type T at compile time. This prevents type confusion errors common in C when using void* or untagged unions without careful management.
  3. Compile-Time Safety Checks: Rust’s ownership and borrowing rules prevent common C errors like dangling pointers or data races when accessing collection elements, catching potential issues before runtime.

While providing these safety guarantees, Rust collections are designed for performance. Techniques like amortized constant-time appending to Vec<T> mean performance is often comparable to well-written C code using dynamic arrays, but with a substantially lower risk of memory-related bugs.

The primary collection types we will cover are:

  • Vec<T>: A growable, contiguous array, often called a vector. Analogous to C++’s std::vector or a manually managed dynamic array in C.
  • String: A growable, heap-allocated string guaranteed to contain valid UTF-8 encoded text. Conceptually similar to Vec<u8> but specialized for Unicode text.
  • HashMap<K, V>: A hash map for storing key-value pairs, offering fast average-case lookups. Similar to C++’s std::unordered_map or hash table implementations found in various C libraries.

Rust also provides specialized collections like BTreeMap, HashSet, BTreeSet, and VecDeque for specific requirements such as sorted data or double-ended queue operations. All standard collections adhere to Rust’s ownership rules, ensuring predictable and safe memory management.