Step 4 of 6
Array and Vec slices: &[T]
Slices aren't only for text. &v[1..3] is a slice of a vector or array: its type is &[T] (for example &[i32]), a pointer to the first element plus a count of elements.
fn main() {
let temps = vec![14, 17, 21, 19, 16, 12, 10];
let weekdays = &temps[..5];
let weekend = &temps[5..];
println!("weekdays {:?}, weekend {:?}", weekdays, weekend);
println!("{} + {} days", weekdays.len(), weekend.len());
}
weekdays [14, 17, 21, 19, 16], weekend [12, 10]
5 + 2 days
temps: Vec<i32> ┌────────────┐
│ ptr ───────┼───────► [14, 17, 21, 19, 16, 12, 10] (heap)
│ len 7 │ ▲ ▲
│ cap 7 │ │ │
└────────────┘ │ │
weekdays: &[i32] ┌────────────┐ │ │
│ ptr ───────┼───────────┘ │
│ len 5 │ │
└────────────┘ │
weekend: &[i32] ┌────────────┐ │
│ ptr ───────┼───────────────────────────────┘
│ len 2 │
└────────────┘
Functions that take &[T]
A &[T] parameter accepts a vector, an array, or any part of either. A &Vec<T> turns into a &[T] automatically, just like &String turns into &str:
fn total(values: &[i32]) -> i32 {
let mut sum = 0;
for v in values {
sum += v;
}
sum
}
fn main() {
let week = vec![3, 5, 2, 8, 6, 1, 0];
let fixed = [10, 20, 30];
println!("{}", total(&week)); // &Vec<i32> becomes &[i32]
println!("{}", total(&week[..5])); // part of it
println!("{}", total(&fixed)); // an array
println!("{}", total(&[])); // an empty slice
}
25
24
60
0
Workplace note: it's the same advice as for text: prefer &[T] over &Vec<T> for parameters (clippy's ptr_arg lint again). &str is to String what &[T] is to Vec<T>: a borrowed view that doesn't care who owns the data.
What you can do with a &[T]:
.len()and.is_empty()- index it,
s[i], and slice it again,&s[a..b] - loop over it:
for x in sgives a&Tfor each element s.contains(&x): isxin it?s.split_at(i): two slices, before and afteri
fn main() {
let scores = [88, 92, 75, 64, 99, 81];
let (first_half, second_half) = scores.split_at(3);
println!("{:?} | {:?}", first_half, second_half);
println!("has a 99: {}", scores.contains(&99));
}
[88, 92, 75] | [64, 99, 81]
has a 99: true
Common mistakes
&Vec<T>parameters. They work, but callers with an array or a part of a vector can't use them. Take&[T].- Passing the vector instead of a reference:
error[E0308]: mismatched types(expected `&[i32]`, found `Vec<{integer}>`) with the helpconsider borrowing here. - Moving out of a slice:
let first = names[0];with a&[String]iserror[E0508]: cannot move out of type `[String]`, a non-copy slice. As with vectors, borrow (&names[0]) or clone. - Out-of-range slices panic, like out-of-range indexes:
&v[3..10]on a 5-element vector.
Your task
Write average, which returns the average of a slice of f64s, or 0.0 for an empty slice. The tests call it with a vector, an array and part of a vector.
Challenge 2
Write count_above, which returns how many values in the slice are greater than limit. The tests call it with a vector, an array and part of a vector.
Challenge 3
Write total(values: &[i32]) -> i32 and use it to finish main: split the numbers into two halves (the first half gets numbers.len() / 2 elements, so the second half gets the extra one for odd counts) and print each half with its total. For the input 3 5 2 8 6 it prints:
first half [3, 5]: 8
second half [2, 8, 6]: 16
Previous: Returning slices: first_word Next: Mutable slices: &mut [T]