8.2.0. Chapter Overview
Chapter 8 is mainly about common collections in Rust. Rust provides many collection-like data structures, and these collections can hold many values. However, the collections covered in Chapter 8 are different from arrays and tuples.
The collections in Chapter 8 are stored on the heap rather than on the stack. That also means their size does not need to be known at compile time; at runtime, they can grow or shrink dynamically.
This chapter focuses on three collections: Vector, String, and HashMap.
If you find this helpful, please like, bookmark, and follow. To keep learning along, follow this series.
8.2.1. How Vector and Enum Complement Each Other
Although Vector can grow or shrink dynamically, all of its elements must still be the same data type. But sometimes we need to store different types of data on the heap. What should we do in that case?
Remember the enum type introduced in [6.1. Enums]? Enum variants can carry attached data, and that attached data can be of different types. Most importantly, the variants all belong to the same enum type. In other words, all variants are the same type, so they can be stored in a Vector.
This allows us to use an enum to make it possible to store different data types inside a Vector.
8.2.2. Vector + enum
Letβs look at a practical example of using Vector plus an enum:
enum SpreadSheetCell {
Int(i32),
Float(f64),
Text(String),
}
fn main() {
let row = vec![
SpreadSheetCell::Int(5567),
SpreadSheetCell::Text("up up".to_string()),
SpreadSheetCell::Float(114.514),
];
}
This example simulates the behavior of Excel cells. A cell can store only one of the following: an integer, a floating-point number, or a string. So we define the SpreadSheetCell enum, which has three variants used to store integers (Int), floating-point numbers (Float), and strings (Text).
In the main function, we declare the variable row to store one row of cells. Because the number of cells in a row is not fixed, we need a Vector to store them. In this example, the Vector is initialized with three cells: the first stores the integer 5567, the second stores the string "up up", and the third stores the floating-point number 114.514.
Through this example, we can see that by using an enum that can carry data, we can indirectly store different data types in a Vector.
So why does Rust need to know the element type of a Vector at compile time? Because only then can Rust determine how much heap memory is needed to hold the Vector. In addition, if different element types were allowed in a Vector, some bulk operations on the elements might be valid for some types but invalid for others, which would cause the program to fail. Using an enum together with a match expression allows Rust to know all possible cases in advance at compile time, so it can handle them correctly at runtime.
In this example, Vector does make it possible to store different data types, but only if we know exactly what the possible data types are, in other words, if the set is exhaustive. If the type has infinitely many possibilities, or is non-exhaustive, then even an enum cannot help, because the enum cannot even be defined. For such cases, Rust provides traits, but that will be covered later.
Top comments (0)