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



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:

RUST
// 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

RUST
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; push add elements (the array automatically resizes); pop remove the last element. No need to specify a size—Vec automatically manages memory on the heap.



3. Dynamic Array Vec

(1) Concept Overview

100%
graph LR
    A[Vec&lt;T&gt; 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:

TEXT 📖 Display only
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
RUST
// ============================================
// 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:

TEXT 📖 Display only
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"] or vec![0; 5] (5 zeros). push appends to the end, pop pops from the end (returns Option<T>). len() returns the number of elements in the list.


▶ Example 2: Insert/Remove and Capacity Management (Difficulty ⭐⭐)

Output:

TEXT 📖 Display only
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()>
RUST
// ============================================
// 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:

TEXT 📖 Display only
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. capacity is the amount of memory allocated for Vec (which may be greater than len), and shrink_to_fit() frees the excess space. .get() Ensures safe access; in case of an out-of-bounds access, it returns None instead of causing a panic.


▶ Example 3: Vec Traversal and Iteration Methods (Difficulty ⭐⭐)

Output:

TEXT 📖 Display only
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>
RUST
// ============================================
// 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:

TEXT 📖 Display only
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: &v for read-only iteration, and &mut v for 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:

TEXT 📖 Display only
Array to Vec: <vec_from_arr>
Via iter: <vec_via_iter>
Vec to array: <ok_array>
Slice of array: <slice>
Squares: <squares>
Repeated: <repeated>
RUST
// ============================================
// 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:

TEXT 📖 Display only
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:

TEXT 📖 Display only
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>
RUST
// ============================================
// 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:

TEXT 📖 Display only
=== 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), and map/filter/sum (functional statistics). retain is more suitable for batch deletion than remove.


❓ FAQ

Q What happens when Vec resizes? Is the performance good?
A When Vec is full, it allocates a new block of memory that is twice as large, copies the old data to it, and frees the old memory.
Q How should I choose between Vec and an array?
A If the exact number of elements is known at compile time and the number is small, use an array; if the number varies dynamically or is unknown, use Vec.
Q What is the difference between vec!["a", "b"] and vec!["a"; 2]?
A The former is a list of elements (each element is calculated independently), while the latter is a duplicate of the same value.
Q What is the difference between .iter() and into_iter()?
A .iter() returns a reference (without transferring ownership), while into_iter() consumes the Vec and returns an iterator that holds ownership.
Q Since Vec data is stored on the heap, what does the Vec variable on the stack contain?
A The stack contains three usize values: a pointer to the heap data, the length (len), and the capacity (capacity), totaling 24 bytes (on a 64-bit system).

📖 Summary


📝 Exercises

  1. Difficulty ⭐: Create a Vec<i32> containing the numbers 1 through 10, use push to add 11 and 12, then use pop to remove the last 3 elements, and finally print Vec.
  2. 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 in main using vec![1, 2, 3, 4, 5, 6, 7, 8]; the result should be [1, 3, 5, 7].
  3. Difficulty ⭐⭐⭐: Simulate a shopping cart program. Define a struct Item { name: String, price: f64, quantity: u32 }. Create a Vec<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 in main.
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏