[Avg. reading time: 16 minutes]
Vector Datatype
A Vector (Vec
- Size can grow or shrink at runtime
- Stores elements of the same type
- Allocated on the heap
- Very commonly used in real-world Rust programs
Dynamic Arrays
Unlike fixed-size arrays [T; N], a Vec
// Vector fn main(){ let mut my_vec = Vec::new(); my_vec.push("Rachel"); my_vec.push("Monica"); my_vec.push("Phoebe"); println!("{:?}",my_vec); }
Capacity() vs Len()
capacity() number of elements the vector can hold (without reallocating memory). This is usually larger than or equal to the number of elements currently in the vector.
len() number of elements.
Inspecting Memory
use std::mem; fn main(){ let mut my_vec = Vec::new(); my_vec.push("Rachel"); my_vec.push("Monica"); my_vec.push("Phoebe"); println!("Vector Value {:?}", my_vec); println!("Address of Vec struct: {:p}", &my_vec); println!("Heap data pointer: {:p}", my_vec.as_ptr()); println!("Length: {}", my_vec.len()); println!("Capacity: {}", my_vec.capacity()); println!("Heap bytes allocated: {}", my_vec.capacity() * mem::size_of::<String>()); my_vec.push("Ross"); my_vec.push("Chandler"); my_vec.push("Joey"); println!("Vector Value {:?}", my_vec); println!("Address of Vec struct: {:p}", &my_vec); println!("Heap data pointer: {:p}", my_vec.as_ptr()); println!("Length: {}", my_vec.len()); println!("Capacity: {}", my_vec.capacity()); println!("Heap bytes allocated: {}", my_vec.capacity() * mem::size_of::<String>()); }
Len vs Allocated Capacity
["Rachel", "Monica", "Phoebe", _empty_]
["Rachel", "Monica", "Phoebe", "Ross", "Chandler", "Joey", _empty, _empty_]
Capacity common growth pattern
0 → 4 → 8 → 16 → 32 → ...
Room 126 - Classroom Capacity vs Number of students*
The vector structure itself lives on the stack, but its elements live on the heap.
A Vec internally stores:
+-------------------------+
| v (Vec<String>) |
|-------------------------|
| ptr ----+--------------|----+
| len = 3 | | |
| cap = 4 | | |
+-------------------------+ |
|
v
HEAP
with_capacity()
The with_capacity() method in Rust is used to create a new, empty growable collection (like Vec or String) that pre-allocates a specific amount of memory on the heap.
This allows the collection to hold at least the specified number of elements without needing to reallocate memory as you add items, which can improve performance.
fn main() { let mut friends_default: Vec<String> = Vec::new(); let mut friends_withcapacity: Vec<String> = Vec::with_capacity(5); println!("friends_default Initial len: {}", friends_default.len()); println!("friends_default Initial cap: {}", friends_default.capacity()); println!("friends_withcapacity Initial len: {}", friends_withcapacity.len()); println!("friends_withcapacity Initial cap: {}", friends_withcapacity.capacity()); friends_default.push("Rachel".to_string()); friends_default.push("Monica".to_string()); friends_default.push("Phoebe".to_string()); friends_withcapacity.push("Rachel".to_string()); friends_withcapacity.push("Monica".to_string()); friends_withcapacity.push("Phoebe".to_string()); println!("friends_default Final len: {}", friends_default.len()); println!("friends_default Final cap: {}", friends_default.capacity()); println!("friends_withcapacity Final len: {}", friends_withcapacity.len()); println!("friends_withcapacity Final cap: {}", friends_withcapacity.capacity()); }
reserve()
Increases capacity after creation.
fn main(){ let mut friends = Vec::new(); friends.push("Rachel".to_string()); friends.push("Monica".to_string()); println!("friends before len: {}", friends.len()); println!("friends before cap: {}", friends.capacity()); friends.reserve(10); println!("friends after len: {}", friends.len()); println!("friends after cap: {}", friends.capacity()); }
Vector with Datatypes
String Literal
fn main(){ let mut my_vec: Vec<&str> = Vec::new(); my_vec.push("Rachel"); my_vec.push("Monica"); my_vec.push("Phoebe"); println!("{:?}",my_vec); }
String Object
fn main(){ let mut my_vec: Vec<String> = Vec::new(); my_vec.push("Rachel".to_string()); my_vec.push("Monica".to_string()); my_vec.push("Phoebe".to_string()); println!("{:?}",my_vec); }
Storing String literal on i32 (Error)
fn main(){ let mut my_vec: Vec<i32> = Vec::new(); my_vec.push("Rachel"); my_vec.push("Monica"); my_vec.push("Phoebe"); println!("{:?}",my_vec); }
Storing String Literal on String Object (Error)
fn main(){ let mut my_vec: Vec<String> = Vec::new(); my_vec.push("Rachel"); my_vec.push("Monica"); my_vec.push("Phoebe"); println!("{:?}",my_vec); }
Vec Macro
- Allocates a Vec
- Infers the type
- Inserts elements
- Sets capacity efficiently
Without vec!
let mut friends = Vec::new();
friends.push("Rachel");
friends.push("Monica");
friends.push("Phoebe");
Using vec!
fn main(){ let friends = vec!["Rachel", "Monica", "Phoebe"]; println!("{:?}", friends); }
Variables created using vector macro are also dynamic, stored in heap and reserved with more capacity.
fn main() { // Create a vector using the vec! macro let numbers = vec![2, 4, 6, 8, 10, 12, 14, 16]; // Borrow different slices from the vector let slice_one = &numbers[2..6]; // Index 2 up to (but not including) 6 let slice_two = &numbers[2..]; // Index 2 to end let slice_three = &numbers[..6]; // Start to index 6 (exclusive) let slice_four = &numbers[..]; // Entire vector as a slice println!("Original Vector : {:?}", numbers); println!("Slice [2..6] : {:?}", slice_one); println!("Slice [2..] : {:?}", slice_two); println!("Slice [..6] : {:?}", slice_three); println!("Slice [..] : {:?}", slice_four); }
[2, 4, 6, 8, 10, 12, 14, 16]
0 1 2 3 4 5 6 7
[start..end] : start is inclusive - end is exclusive
Convert Array to Vector
This example demonstrates
- Fixed-size array [T; N]
- Converting array into Vec
- Type inference using Vec<_>
- Inspecting types at runtime
use std::any::type_name; fn main() { // Fixed-size array (stack allocated) let arr = [1_i8, 2, 3, 4]; // Explicit type conversion let vec_explicit: Vec<i8> = arr.into(); // Type inference let vec_inferred: Vec<_> = arr.into(); println!("Array : {:?}", arr); println!("Vec explicit: {:?}", vec_explicit); println!("Vec inferred: {:?}", vec_inferred); println!("\nType Information:"); print_type(&arr); print_type(&vec_explicit); print_type(&vec_inferred); } fn print_type<T>(_: &T) { println!("{}", type_name::<T>()); }
Sort the Vector
fn main() { let mut vec = vec![14, 33, 12, 3223, 2211, 9122, 3, 67]; vec.sort(); println!("Sorted: {:?}", vec) }