Skip to content
Select theme

What is the difference between a Vec and a slice?

Short answer: A Vec<T> owns its buffer: it allocates on the heap, grows when full, and frees the memory when dropped. A slice, &[T], owns nothing — a pointer and a length into a buffer that belongs to someone else.

Ask for a slice by value and the compiler says why. In a fresh project (cargo new slice-demo), replace src/main.rs with this and run cargo build:

error[E0277]: the size for values of type `[i32]` cannot be known at compilation time
--> src/main.rs:1:16
|
1 | fn sum(values: [i32]) -> i32 {
| ^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `[i32]`
help: function arguments must have a statically known size, borrowed slices always have a known size
|
1 | fn sum(values: &[i32]) -> i32 {
| +
For more information about this error, try `rustc --explain E0277`.

That help line is the answer: [T] alone has no statically known size, so only the views travel, &[T] for reading and &mut [T] for writing. A view is two machine words, a pointer and a length. The Vec is the owner: three words, a pointer, a length and a capacity, pointing at one heap allocation.

vec![1, 2, 3] makes one allocation; dropping the Vec frees it. Growing past the capacity allocates a bigger buffer and copies the elements across. None of that belongs to a slice: borrowing one allocates nothing, letting it go frees nothing. The owner decides when the memory goes back.

A Vec can do everything a slice can: len, iter, first, indexing, sort. They belong to [T], and Vec<T> implements Deref<Target = [T]>, so they resolve on a Vec directly. The reverse isn’t true: a slice can’t change size, so there’s no push, no pop (E0599), no capacity.

A slice can view a Vec’s buffer, an array on the stack, or a window into either. &numbers[..] spells the whole buffer, &numbers[1..] a window from the second element on, and &numbers is accepted wherever a &[i32] is expected, by deref coercion. A shared slice is Copy; a Vec is not, so passing one to a function moves it.

Next in this chapter: how to accept both a Vec and a slice in one function.