What is the difference between arrays and vectors in Rust? The answer is: They are both fundamentally the same thing, trust me bro 🫠*. Same same but different.*
You see to understand the difference between rust arrays and vectors we have to look back into Data structures. What is an Array (or list if you come from a Python background)?
In short terms, an array is a contiguous data structure stored on the stack. Now if you did your homework you would know there a two major types of arrays, Dynamic and Static Arrays.
This article is not about Data Structures in general so I won’t go into details, but all you have to know is Dynamic arrays are simply static arrays with a bunch of wrappers to handle fluidity, in rust this wrapper is called a Vector.
So, fundamentally they are both the same thing, with slight implementation differences. These differences and trade-offs as well as special features as well as some guidelines for usage as some of the things you should know by the time we are done here.
💡 Vectors are Dynamic Arrays while Arrays are Static Arrays.
Now we are over with the introduction, let's get into some details.
First: Definition and Basic Syntax
Arrays
Fixed-size: Size determined at compile time.
Stack-allocated: Memory lives on the stack.
Type signature:
[T; N]
, whereT
is the element type andN
is a compile-time constant.
// Declare an array of 5 integers
let arr: [i32; 5] = [1, 2, 3, 4, 5];
// Initialize all elements to 0
let zeros = [0; 10]; // Array of 10 zeros
Vectors
Dynamic size: Can grow or shrink at runtime.
Heap-allocated: Memory is managed dynamically on the heap.
Type signature:
Vec<T>
.
// Create a vector with initial values
let mut vec = vec![1, 2, 3];
// Add elements dynamically
vec.push(4); // Now contains [1, 2, 3, 4]
Key Differences
Now we know how to define both structures and you know how to identify each of them in code, and how they are handled by your computer, we should now know the differences.
Feature | Arrays ( | Vectors ( |
---|---|---|
Size | Fixed at compile time. | Dynamic (can resize at runtime). |
Memory Allocation | Stack-allocated. | Heap-allocated. |
Mutability | The entire array is immutable/mutable. | Individual elements or sizes can be changed. |
Performance | Faster access (no heap overhead). | Slightly slower due to heap management. |
Methods | Limited functionality. | Rich API ( |
Memory and Ownership
Arrays
Stack-bound: Memory is contiguous and allocated when the array is declared.
Fixed ownership: The entire array is moved or borrowed as a single unit.
Slices: To borrow some part of an array you can use a slice
fn print_array(arr: [i32; 3]) {
println!("{:?}", arr);
}
let a = [1, 2, 3];
print_array(a); // Ownership of `a` is moved
Vectors
Heap flexibility: Data lives on the heap, but the vector itself (pointer, capacity, length) is stored on the stack.
Mutable borrowing: Allows partial mutation (e.g., modify elements without moving the entire vector).
fn double_elements(vec: &mut Vec<i32>) {
for num in vec.iter_mut() {
*num *= 2;
}
}
let mut v = vec![1, 2, 3];
double_elements(&mut v); // Mutably borrows `v`
Common Operations
Array Operations
Accessing elements:
let arr = [10, 20, 30];
let first = arr[0]; // 10
Iteration:
for num in arr.iter() { println!("{}", num); }
Limitations: Since the size is fixed you cannot push or pop unlike in vectors
Vector Operations
Adding/removing elements:
let mut vec = vec![1, 2]; vec.push(3); // [1, 2, 3] vec.pop(); // [1, 2]
Resizing:
vec.resize(5, 0); // [1, 2, 0, 0, 0]
Slicing:
let slice = &vec[1..3]; // [2]
Conversion Between Arrays and Vectors
You might find yourself in a situation where for some reason you want to convert from an array to a vector. Here is how to do it:
Array to Vector:
By calling the to_vec()
inbuilt method, you effectively create a Vector type from the contents of your arrays, the array is then dropped and the handles for it are now switched to a Vector instead
let arr = [1, 2, 3];
let vec = arr.to_vec(); // Converts to Vec<i32>
Vector to Array
On the other hand, to convert from a vector to an array (to be honest I do not know how you found yourself doing this ) you would need to call the try_into trait method.
This trait method would try to convert one type to another, luckily the trait Into
array is implemented for Vectors. This operation is fallible — meaning it returns a result — so you should handle that by calling an unwrap_or_else
or using a match statement
(for more details on error handling check out this article). Like before this would effectively create an array type and drop the vector type.
💡Do not forget to specify the array length in the type conversion
let vec = vec![1, 2, 3];
// 3 is the array length , while i32 is the type
// try_into needs this type declaration to be able to parse properly
let arr: [i32; 3] = vec.try_into().unwrap(); // Panics if sizes differ
So, when do you use arrays or Vectors
You should use arrays when :
You need a fixed-size collection (e.g., coordinates
[x, y, z]
).Stack memory is preferred for performance (small datasets).
Compile-time size guarantees are required.
And use Vectors when:
The size is unknown at compile time (e.g., user input).
You need dynamic resizing (e.g., building a list incrementally).
You want access to rich methods (e.g., sorting, filtering).
Use arrays for static read-only operations and use vectors for anything else
What are the Performance Costs and Considerations around them?
Arrays: Faster for small, fixed-size data due to stack allocation and no heap overhead.
Vectors: Slightly slower due to heap allocation, but more flexible. Pre-allocate capacity to minimize reallocation:
Rust's Zero Cost Abstraction approach would save you some performance losses when using vectors but nothing beats the algorithm.
In other to save yourself some extra performance cost, if you can, specify the vector capacity.
The reason this works is because: If we know the vector capacity, the vector init Array size is pre-set removing that performance overhead that comes with inserts in a vector.
let mut vec = Vec::with_capacity(100);
💡If you know the expected Vector capacity, you can always set it to increase performance
In Conclusion
Array and Vectors are almost the same concepts but serve slightly different purposes. Start to see them like: Static Arrays and Dynamic Arrays.
If you are in a scenario where requiring fixed-size, stack-allocated data with minimal overhead is necessary then you should use Arrays, else you can use vectors as it would be much better when providing dynamic resizing and heap flexibility for unpredictable or growing Lists.
If you have a question feel free to reach out to me on LinkedIn.
Also, check out this course on backend engineering in Rust, which should help you master Rust from basics to advanced.