# Vector Vectors allow you to store more and one value in a single data structure that puts all of the values next to each other in the memory Vectors can only store values of the same type hence the generic in the ``Vec`` keyword useful when you have a list of items, like the lines of text in a file or the prices of items in a shopping cart (this would be better with a hash map (more obj relation)) ## Creating a new Vector to create a empty vector we call ``let v: Vec = Vec::new();`` Type annotation is need because a value is not given here and the compiler will not know what type of data will be stored here hence why the generic must be specified instead of inferred More often a Vector will have initial values and Rust will infer the type of value stored Rust has a Macro for this ``vec!`` this will create a new vector that holds the values given to it ```rust let v = vec![1, 2, 3]; ``` this is implicitly a ``Vec`` ## Updating a Vector Add values to the vector you can use the push method ```rust let mut v = Vec::new(); v.push(5); v.push(6); v.push(7); v.push(8); ``` This must be mutable in order to do this this is another way to implicitly start up a ``Vec`` variable ## Reading Elements of Vectors There a two ways to reference a value sorted in a vector via indexing or by using the ``get`` method here is an example of using both ```rust let v = vec![1, 2, 3, 4, 5]; let third: &i32 = &v[2]; println!("The third element is {third}"); let third: Option<&i32> = v.get(2); match third { Some(third) => println!("The third element is {third}"), None => println!("There is no third element."), } ``` this uses the index of 2 to get the third element vectors are indexed starting at zero using ``&`` and ``[]`` gives us a reference to the element at the index value when using get it returns an ``Option<&T>`` which is a referenced generic which is then specified to a i32 as you can see the ``get`` method is more safe because it accounts for when it way be null value or out of range ```rust let does_not_exist = &v[100]; let does_not_exist = v.get(100); ``` the first one would cause the program to panic but the second wouldn't cause a panic instead it would require the situation to be dealt with in a match pattern for when it is None see [``Option``](data_types.md#The Option Enum and Advantages over Null types) for more details when the program has a valid reference the borrow checker ensures this reference and any other references must be valid to the contents of where it refers to. One case where this could easily be broken is creating a reference then trying to add an element to the end then trying to use the reference later in the function ```rust let mut v = vec![1, 2, 3, 4, 5]; let first = &v[0]; v.push(6); println!("The first element is: {first}"); ``` this would result in a borrow checker error because vector.push uses a mutable reference to the vector check here for more details [[ownership#Rules]] This is also due to how vectors are implemented, what happens when the allocated space on memory runs out, then it must be copied to another place in memory, then the old vector is freed In that case where the reference is pointing to may be deallocated and therefore not valid For implementation details of ``Vec`` type see [The Rustonomicon](https://doc.rust-lang.org/nomicon/vec/vec.html) ## Iterating Over the Values in a Vector We would rather iterate over the elements rather than over the index ands access each one one at a time here is an example that give an immutable reference for each element ```rust let v = vec![100, 32, 57]; for i in &v { println!("{i}"); } ``` can also iterate over mutable referneces here is an example where we add 50 to each element using the ``*`` or dereference operator to assign values to the reference ```rust let mut v = vec![100, 32, 57]; for i in &mut v { *i += 50; } ``` We cannot add or remove from the vector when iterating over it because of borrow checking rules, the reference to the whole vector prevents that ## Using an Enum to Store Multiple Types Vectors can only store values that are of the same type, this can be inconvenient sometimes. But you can use variants of an enum which is considered the same type this is allowed ```rust enum SpreadsheetCell { Int(i32), Float(f64), Text(String), } let row = vec![ SpreadsheetCell::Int(3), SpreadsheetCell::Text(String::from("blue")), SpreadsheetCell::Float(10.12), ]; ``` Rust needs to know what types will be in the vector at compile time so it knows exactly how much memory to store per element in the vector so it must be specific when initializing a vector using an enum plus a match ensures that all possible cases are handled which ensures that a panic will not happen If you do not know the exhaustive set of types a program will get at runtime to store in a vector then the enum technique will not work instead use a trait object Here is a the API documentation for a Vector with all of the methods defined on a ``Vec`` For example a ``pop`` removes and returns the last element ## Dropping a Vector Drops Its Elements This is like any other struct, when a vector is freed/goes out of scope then so will its inner elements