Skip to content
Select theme

How to accept both a Vec and a slice in one function

Short answer: Declare the parameter &[T]. A &Vec<T> and a &[T; N] both coerce to &[T] at the call site, so one function takes a Vec, an array, a window into either, or a slice that already exists — and nobody clones anything.

In a fresh project (cargo new slice-param), replace src/main.rs with this and run cargo run:

10
60
9
10

All four calls reach the same function. &numbers is a &Vec<i32> and &array is a &[i32; 3]; where a &[i32] is expected, the compiler coerces both, because a Vec derefs to a slice and an array is a slice with its length in the type. &numbers[1..] is already a slice — a window from the second element on. slice is a &[i32] and needs nothing done to it. The explicit spellings, &numbers[..] and numbers.as_slice(), produce the same type.

Type the parameter &Vec<i32> and the array call stops compiling:

error[E0308]: mismatched types
--> src/main.rs:7:26
|
7 | println!("{}", total(&numbers));
| ----- ^^^^^^^^ expected `&Vec<i32>`, found `&[{integer}; 3]`
| |
| arguments to this function are incorrect
|
= note: expected reference `&Vec<i32>`
found reference `&[{integer}; 3]`
note: function defined here
--> src/main.rs:1:4
|
1 | fn total(values: &Vec<i32>) -> i32 {
| ^^^^^ -----------------
For more information about this error, try `rustc --explain E0308`.

Worse, a caller holding a slice has to build a Vec to call you — an allocation and a copy of every element, on every call:

6

to_vec() is the clone the &[T] parameter removes. If the function only reads, &[T] is the signature that costs callers the least.

The same rule covers mutation. A &mut [i32] parameter accepts a &mut Vec<i32>, and the writes land in the Vec’s own buffer:

[2, 4, 6]

&mut numbers is reborrowed as a mutable view for the call — what reborrowing is has the details — and the Vec is still usable afterwards, because it never moved.

A generic parameter, fn sum<T: AsRef<[i32]>>(values: T), also accepts a Vec and an array, and it takes an owned Vec as well. For a function that only reads, that is more signature than the job needs: &[T] already accepts every caller above, and coercion does the work.

Next in this chapter: how to sort a Vec.