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.
Three names, one buffer
Section titled “Three names, one buffer”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:
fn sum(values: [i32]) -> i32 { values.iter().sum()}
fn main() {}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.
Who owns the buffer
Section titled “Who owns the buffer”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.
What each one can do
Section titled “What each one can do”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.
Where the view can point
Section titled “Where the view can point”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.
Related
Section titled “Related”- How to pass a Vec to a function without cloning it —
&[T]as a parameter - What is the difference between String and &str? — the same split, for text
- Why can’t I modify a Vec while iterating over it? — the borrow, from the loop
Next in this chapter: how to accept both a Vec and a slice in one function.