Rust: Rust Vectors (Vec)
Last updated: 2026-08-26
Vec<T>(vector) is the most commonly used dynamic array in the Rust standard library—it can grow or shrink at runtime, and all data is allocated on the heap. It is Rust’s equivalent of an “ArrayList” or a “Python list.”
If arrays are like "fixed-size storage lockers," then Vec is like a "scalable warehouse"—it automatically expands when space runs out, so you don't have to manually manage memory.
1. What You'll Learn
- Create dynamic arrays using the
vec!macro andVec::new() - Use push/pop to add or remove elements from the end
- Use
insertandremoveto add or remove elements in the middle - Understand the difference between capacity and length
- Traversing and iterating over Vecs, and converting between Vecs and arrays
2. The Story of a Supermarket Cashier
(1) Frustration: Not knowing the size of the shopping cart
Tom is developing a supermarket checkout system. The customer's shopping cart:
// The problem with arrays -- you must know how many items in advance!
let cart: [&str; 3] = ["milk", "bread", "eggs"];
// Customer says: "Add one more cola"
// Arrays can't grow dynamically -- you need to redeclare...
let mut cart2 = ["milk", "bread", "eggs", "cola"];
// Customer: "Remove eggs, add butter instead"
// Modify every time? This is painful!
The size of an array is fixed at compile time. But with a shopping cart—you don’t know whether a customer will buy 3 items or 30. You need a data structure that grows dynamically at runtime.
(2) Solution for Rust Vec
fn main() {
// Start with an empty cart
let mut cart: Vec<&str> = Vec::new();
// Customer adds items one by one
cart.push("milk");
cart.push("bread");
cart.push("eggs");
println!("Cart has {} items: {:?}", cart.len(), cart);
// Customer adds more
cart.push("cola");
println!("Added cola: {:?}", cart);
// Customer removes an item
cart.pop();
println!("Removed last: {:?}", cart);
// Check what's inside
println!("Current cart: {:?}", cart);
}
Vec::new()Create an empty dynamic array;pushadd elements (the array automatically resizes);popremove the last element. No need to specify a size—Vec automatically manages memory on the heap.
3. Dynamic Array Vec
(1) Concept Overview
graph LR
A[Vec<T> dynamic array] --> B[Creation]
A --> C[CRUD operations]
A --> D[Capacity management]
A --> E[Conversion]
B --> B1[Vec::new()]
B --> B2[vec! macro]
B --> B3[collect()]
C --> C1[push / pop]
C --> C2[insert / remove]
C --> C3[index / .get()]
D --> D1[capacity: allocated]
D --> D2[len: actual use]
D --> D3[shrink_to_fit]
E --> E1[From array]
E --> E2[Back to array]
(2) Comparing Vec and Arrays
| Dimension | Array [T; N] |
Vector Vec<T> |
|---|---|---|
| Size | Fixed at compile time | Grows dynamically at runtime |
| Allocation Location | Stack (usually) | Heap |
| Scaling | Not supported | Automatic 2x scaling |
| API Richness | Limited | Extremely Rich |
| Access Speed | Extremely fast (contiguous on the stack) | Extremely fast (contiguous on the heap) |
| Use Cases | Fixed size, allocated on the stack | Unknown number, frequent additions and removals |
| Performance Overhead | None | push may trigger reallocation |
(3) Quick Reference for Common Vec Methods
| Method | Return Type | Description | Time Complexity |
|---|---|---|---|
push(val) |
() |
Append to the end | O(1) amortized |
pop() |
Option<T> |
Tail pop-up | O(1) |
insert(idx, val) |
() |
Insert at a specified position | O(n) |
remove(idx) |
T |
Remove at a specified position | O(n) |
get(idx) |
Option<&T> |
Secure Access | O(1) |
len() |
usize |
Number of elements | O(1) |
capacity() |
usize |
Allocated Capacity | O(1) |
clear() () Clear O(n) |
|||
contains(&val) |
bool |
Contains | O(n) |
sort() |
() |
Sort in place | O(n log n) |
dedup() |
() |
Remove duplicates (must be sorted first) | O(n) |
retain(f) |
() |
Keep elements that meet the criteria | O(n) |
shrink_to_fit() |
() |
Free up excess capacity | — |
(4) Comparison of Vec Iteration Methods
| Method | Syntax | Ownership | Available in Vec |
|---|---|---|---|
| Borrowed Iteration | for x in &v |
Read-Only Reference | Available |
| Variadic traversal | for x in &mut v |
Variadic references | Available (fixed) |
| Consumption Traversal | for x in v |
Transfer Ownership | Not Available |
| Iterator | v.iter() |
Read-only reference | Available |
| Enumeration Iteration | v.iter().enumerate() |
Read-Only Reference + Index | Available |
4. Example
▶ Example 1: The vec! macro and push/pop (Difficulty ⭐)
Output:
v1: <v1>, len=<v1.len()>
v2: [apple, banana, cherry], len=3
v3 (five zeros): <v3>
After push: [apple, banana, cherry]
Popped: <last>
After pop: [apple, banana, cherry]
v2 empty? false
v2[0] = apple
v2 length: 3
// ============================================
// Vec: vec! macro, push, pop, len, is_empty
// ============================================
fn main() {
// Method 1: Vec::new()
let mut v1: Vec<i32> = Vec::new();
v1.push(10);
v1.push(20);
v1.push(30);
println!("v1: {:?}, len={}", v1, v1.len());
// Method 2: vec! macro (most common)
let mut v2 = vec!["apple", "banana", "cherry"];
println!("v2: {:?}, len={}", v2, v2.len());
// Method 3: vec! with repeated value
let v3 = vec![0; 5];
println!("v3 (five zeros): {:?}", v3);
// push: add to the end
v2.push("date");
println!("After push: {:?}", v2);
// pop: remove from the end
let last = v2.pop();
println!("Popped: {:?}", last);
println!("After pop: {:?}", v2);
// is_empty
println!("v2 empty? {}", v2.is_empty());
// Access by index
println!("v2[0] = {}", v2[0]);
// len
println!("v2 length: {}", v2.len());
}
Output:
v1: [10, 20, 30], len=3
v2: ["apple", "banana", "cherry"], len=3
v3 (five zeros): [0, 0, 0, 0, 0]
After push: ["apple", "banana", "cherry", "date"]
Popped: Some("date")
After pop: ["apple", "banana", "cherry"]
v2 empty? false
v2[0] = apple
v2 length: 3
vec!is the most common way to create a list—vec!["a", "b", "c"]orvec.pushappends to the end,poppops from the end (returnsOption<T>).len()returns the number of elements in the list.
▶ Example 2: Insert/Remove and Capacity Management (Difficulty ⭐⭐)
Output:
Initial -- len: <cart.len()>, cap: <cart.capacity()>
After 3 pushes -- len: <cart.len()>, cap: <cart.capacity()>
After insert at 1: <cart>
Now -- len: <cart.len()>, cap: <cart.capacity()>
Removed: <removed>
After remove at 2: <cart>
First item: <item>
Empty cart!
Item at 99: <item>
Index 99 is out of bounds!
After shrink -- len: <cart.len()>, cap: <cart.capacity()>
// ============================================
// Vec: insert, remove, capacity vs length
// ============================================
fn main() {
let mut cart: Vec<&str> = Vec::with_capacity(3);
// capacity vs length
println!("Initial -- len: {}, cap: {}", cart.len(), cart.capacity());
cart.push("milk");
cart.push("bread");
cart.push("eggs");
println!("After 3 pushes -- len: {}, cap: {}", cart.len(), cart.capacity());
// insert at arbitrary position
cart.insert(1, "cola"); // insert "cola" at index 1
println!("After insert at 1: {:?}", cart);
println!("Now -- len: {}, cap: {}", cart.len(), cart.capacity());
// Capacity may have doubled!
// remove at arbitrary position
let removed = cart.remove(2); // remove element at index 2
println!("Removed: {}", removed);
println!("After remove at 2: {:?}", cart);
// get -- safe access (returns Option<&T>)
match cart.get(0) {
Some(item) => println!("First item: {}", item),
None => println!("Empty cart!"),
}
// Try an out-of-bounds index with get (safe)
match cart.get(99) {
Some(item) => println!("Item at 99: {}", item),
None => println!("Index 99 is out of bounds!"),
}
// shrink_to_fit: reduce capacity to match length
cart.shrink_to_fit();
println!("After shrink -- len: {}, cap: {}", cart.len(), cart.capacity());
}
Output:
Initial -- len: 0, cap: 3
After 3 pushes -- len: 3, cap: 3
After insert at 1: ["milk", "cola", "bread", "eggs"]
Now -- len: 4, cap: 6
Removed: bread
After remove at 2: ["milk", "cola", "eggs"]
First item: milk
Index 99 is out of bounds!
After shrink -- len: 3, cap: 3
insert(idx, val)Inserts at the specified position (shifting subsequent elements to the right),remove(idx)removes the element at the specified position and returns it.capacityis the amount of memory allocated for Vec (which may be greater thanlen), andshrink_to_fit()frees the excess space..get()Ensures safe access; in case of an out-of-bounds access, it returnsNoneinstead of causing a panic.
▶ Example 3: Vec Traversal and Iteration Methods (Difficulty ⭐⭐)
Output:
Prices:
<p>
With 10% tax: [29.9, 49.9, 15.5, 99.0, 8.8]
Item <p>: <i>
Total: <total>
Items above 30: <above_30>
20% discount: <discounted>
// ============================================
// Vec: iteration, mutation, and functional methods
// ============================================
fn main() {
let mut prices = vec![29.9, 49.9, 15.5, 99.0, 8.8];
// Method 1: for-in by reference
print!("Prices: ");
for p in &prices {
print!("{:.1} ", p);
}
println!();
// Method 2: mutable iteration (add tax)
for p in &mut prices {
*p *= 1.1; // 10% tax
}
println!("With 10% tax: {:?}", prices);
// Method 3: .iter().enumerate()
for (i, p) in prices.iter().enumerate() {
println!("Item {}: {:.2}", i, p);
}
// Method 4: functional style -- map, filter, sum
let total: f64 = prices.iter().sum();
println!("Total: {:.2}", total);
let above_30: Vec<f64> = prices.iter()
.filter(|&&p| p > 30.0)
.copied()
.collect();
println!("Items above 30: {:?}", above_30);
let discounted: Vec<f64> = prices.iter()
.map(|p| p * 0.8) // 20% off
.collect();
println!("20% discount: {:?}", discounted);
}
Output:
Prices: 29.9 49.9 15.5 99.0 8.8
With 10% tax: [32.89, 54.89, 17.05, 108.9, 9.68]
Item 0: 32.89
Item 1: 54.89
Item 2: 17.05
Item 3: 108.90
Item 4: 9.68
Total: 223.41
Items above 30: [32.89, 54.89, 108.9]
20% discount: [26.312, 43.912, 13.640000000000002, 87.12, 7.744]
Vec supports multiple iteration methods:
&vfor read-only iteration, and&mut vfor modifying elements. The functional-style methods.iter(),.map(),.filter(), and.sum()make data processing concise and elegant..collect()converts an iterator back to a Vec.
▶ Example 4: Converting Between Vec and Arrays (Difficulty ⭐⭐)
Output:
Array to Vec: <vec_from_arr>
Via iter: <vec_via_iter>
Vec to array: <ok_array>
Slice of array: <slice>
Squares: <squares>
Repeated: <repeated>
// ============================================
// Conversion between Vec and arrays
// ============================================
fn main() {
// Array -> Vec: via .to_vec()
let arr: [i32; 5] = [10, 20, 30, 40, 50];
let vec_from_arr: Vec<i32> = arr.to_vec();
println!("Array to Vec: {:?}", vec_from_arr);
// Array -> Vec: via .iter().copied().collect()
let vec_via_iter: Vec<i32> = arr.iter().copied().collect();
println!("Via iter: {:?}", vec_via_iter);
// Vec -> Array: via try_into() (returns Result)
let vec_data = vec![1, 2, 3, 4];
// let bad_array: [i32; 5] = vec_data.try_into().unwrap(); // PANIC: length mismatch
let ok_array: [i32; 4] = vec_data.try_into().unwrap();
println!("Vec to array: {:?}", ok_array);
// Vec -> slice (zero-cost, no copy)
let slice: &[i32] = &ok_array[1..3];
println!("Slice of array: {:?}", slice);
// Vec from iterator
let squares: Vec<i32> = (1..=5).map(|x| x * x).collect();
println!("Squares: {:?}", squares);
// Vec from repeated value
let repeated = vec!["hello"; 3];
println!("Repeated: {:?}", repeated);
}
Output:
Array to Vec: [10, 20, 30, 40, 50]
Via iter: [10, 20, 30, 40, 50]
Vec to array: [1, 2, 3, 4]
Slice of array: [20, 30]
Squares: [1, 4, 9, 16, 25]
Repeated: ["hello", "hello", "hello"]
Use
.to_vec()to convert an array to a Vec. Use.try_into().unwrap()to convert a Vec to an array—the lengths must match, or a panic will occur. A Vec can be converted to a slice at no cost using&[T]. Creating a Vec from an iterator using.collect()is a common technique.
▶ Example 5: Comprehensive Exercise—Shopping Cart and Price Calculation (Difficulty ⭐⭐⭐)
Output:
Products Unit Price Quantity Subtotal
<"-".repeat(42)>
<item.name> <item.price> <item.quantity> <item.subtotal()>
<"-".repeat(42)>
Total <total>
=== Shopping Cart ===
--- Remove Cola after ---
--- Add Butter + Add Eggs Quantity ---
Before taxes: <total>, Tax(8%): <tax>, Total due: <total + tax>
// ============================================
// Comprehensive Example: Vec Insert, Delete, Update, Query + Functional Iteration
// ============================================
#[derive(Debug, Clone)]
struct Item {
name: String,
price: f64,
quantity: u32,
}
impl Item {
fn new(name: &str, price: f64, quantity: u32) -> Self {
Item { name: name.to_string(), price, quantity }
}
fn subtotal(&self) -> f64 {
self.price * self.quantity as f64
}
}
fn print_cart(cart: &[Item]) {
println!("{:<15} {:>8} {:>6} {:>10}", "Products", "Unit Price", "Quantity", "Subtotal");
println!("{}", "-".repeat(42));
for item in cart {
println!("{:<15} {:>8.2} {:>6} {:>10.2}",
item.name, item.price, item.quantity, item.subtotal());
}
let total: f64 = cart.iter().map(|i| i.subtotal()).sum();
println!("{}", "-".repeat(42));
println!("{:<15} {:>8} {:>6} {:>10.2}", "Total", "", "", total);
}
fn main() {
let mut cart: Vec<Item> = Vec::new();
cart.push(Item::new("Milk", 5.5, 2));
cart.push(Item::new("Bread", 8.0, 1));
cart.push(Item::new("Eggs", 12.5, 3));
cart.push(Item::new("Cola", 3.0, 4));
println!("=== Shopping Cart ===");
print_cart(&cart);
cart.retain(|i| i.name != "Cola");
println!("\n--- Remove Cola after ---");
print_cart(&cart);
cart.push(Item::new("Butter", 15.0, 2));
if let Some(eggs) = cart.iter_mut().find(|i| i.name == "Eggs") {
eggs.quantity += 2;
}
println!("\n--- Add Butter + Add Eggs Quantity ---");
print_cart(&cart);
let total: f64 = cart.iter().map(|i| i.subtotal()).sum();
let tax = total * 0.08;
println!("\nBefore taxes: {:.2}, Tax(8%): {:.2}, Total due: {:.2}", total, tax, total + tax);
let expensive: Vec<&Item> = cart.iter().filter(|i| i.price > 10.0).collect();
println!("Unit Price > 10 Items priced at yuan: {:?}", expensive.iter().map(|i| &i.name).collect::<Vec<_>>());
}
Output:
=== Shopping Cart ===
Products Unit Price Quantity Subtotal
------------------------------------------
Milk 5.50 2 11.00
Bread 8.00 1 8.00
Eggs 12.50 3 37.50
Cola 3.00 4 12.00
------------------------------------------
Total 68.50
--- Remove Cola after ---
Products Unit Price Quantity Subtotal
------------------------------------------
Milk 5.50 2 11.00
Bread 8.00 1 8.00
Eggs 12.50 3 37.50
------------------------------------------
Total 56.50
--- Add Butter + Add Eggs Quantity ---
Products Unit Price Quantity Subtotal
------------------------------------------
Milk 5.50 2 11.00
Bread 8.00 1 8.00
Eggs 12.50 5 62.50
Butter 15.00 2 30.00
------------------------------------------
Total 103.50
Before taxes: 103.50, Tax(8%): 8.28, Total due: 111.78
Unit Price > 10 Items priced at yuan: ["Eggs", "Butter"]
This example combines the use of core Vec operations such as
push,retain(conditional deletion),iter_mut().find()(conditional modification), andmap/filter/sum(functional statistics).retainis more suitable for batch deletion thanremove.
❓ FAQ
vec!["a", "b"] and vec!["a"; 2]?usize values: a pointer to the heap data, the length (len), and the capacity (capacity), totaling 24 bytes (on a 64-bit system).📖 Summary
Vec<T>is a dynamically allocated array on the heap that can be resized at runtime- Creation method:
Vec::new(),vec![],Vec::with_capacity(n) - Tail operations:
pushAdd (O(1) with load balancing),popRemove (O(1)) - Intermediate operation:
insert/remove(O(n), data must be shifted) - Capacity vs. Length:
capacityis the allocated space;lenis the actual number of elements;shrink_to_fitfrees up excess memory - Vecs and arrays can be converted back and forth, and Vecs can be converted to slices at no cost
&[T]
📝 Exercises
- Difficulty ⭐: Create a
Vec<i32>containing the numbers 1 through 10, usepushto add 11 and 12, then usepopto remove the last 3 elements, and finally print Vec. - Difficulty ⭐⭐: Write a function
fn remove_evens(v: &mut Vec<i32>)that removes all even numbers from Vec and keeps the odd ones. Test it inmainusingvec![1, 2, 3, 4, 5, 6, 7, 8]; the result should be[1, 3, 5, 7]. - Difficulty ⭐⭐⭐: Simulate a shopping cart program. Define a
struct Item { name: String, price: f64, quantity: u32 }. Create aVec<Item>shopping cart and implement the following: adding items, deleting items by name, modifying quantities, and printing the total price of the shopping cart. Demonstrate the complete process inmain.