The for loop is another form of loops that can be used in Rust. It is used to loop over elements of an iterator. An iterator is a structure that produces a sequence of value: it could produce the same value indefinitely or produce the elements of a collection. We can get an iterator from a slice, so let's do that to compute the sum of the elements in a slice:
let array = [1, 2, 3, 4];
let mut sum = 0;
for element in &array {
sum += *element;
}
println!("Sum: {}", sum);
The only surprising part here is * in sum += *element. Since we get a reference to the elements of the slice, we need to dereference them in order to access the integers. We used & in front of array to avoid moving it, indeed, we may still want to use this variable after the loop.
Let's write a function that returns the index of an element in a slice, or None if it is not in the slice:
fn index<T: PartialEq>(slice: &[T], target: &T) -> Option<usize> {
for (index, element) in slice.iter().enumerate() {
if element == target {
return Some(index);
}
}
None
}
Note: A partial equivalence relation is both symmetric and transitive, but not reflexive. The Eq trait is used when these three properties are satisfied.
Here, we use again a generic type, but this time we use the PartialEq trait bound to be able to use the == operator on values of the T type. This function returns Option<usize>, meaning that it can either return no value (None) or the index (Some(index)). In the first line of the body, we use slice.iter().enumerate() to get the index in addition to the element of the slice. We use pattern matching right after the for keyword in order to assign the index and the element to variables. Inside the condition, we use the return keyword to return a value early. So if the value is found, it will return the index; otherwise, the loop will end and the None value is returned afterward.
Let's write another function that uses a for loop. It returns the minimum and the maximum of a slice, or None if the slice is empty:
fn min_max(slice: &[i32]) -> Option<(i32, i32)> {
if slice.is_empty() {
return None;
}
let mut min = slice[0];
let mut max = slice[0];
for &element in slice {
if element < min {
min = element;
}
if element > max {
max = element;
}
}
Some((min, max))
}
Here we return multiple values from a function by using a tuple. This time, & is on the left side of in, while previously it was on the right side of it; this is because this for loop is pattern matching against a reference by using &element. This is something we can do in Rust, thus we don't need to dereference the element anymore with *.