Struggle with Rust compiler — 9 Link to heading
Let’s say we want to create an iterator of a slice or a vector in Rust, where the iterator starts from an element at a specified index k rather than from the start index 0. This can be useful for looping over a circular buffer or a ring buffer, for example.
Can you implement the function iter_from() below so that the program prints out exactly 5,6,7,8,9,0,1,2,3,4,?
fn iter_from<T>(slice: &[T], k: usize) -> impl Iterator<Item=&T> {
// todo
}
fn main() {
let array = [0,1,2,3,4,5,6,7,8,9];
for i in iter_from(&array, 5) {
print!("{},", i);
} // 5,6,7,8,9,0,1,2,3,4,
}
Hope it wasn’t too bad. My solution is to use Iterator::chain method (Rust playground link)
fn iter_from<T>(slice: &[T], k: usize) -> impl Iterator<Item=&T> {
slice[k..].iter().chain(slice[..k].iter())
}
Now, here is the real challenge for today — can you implement a mutable variant of the function, i.e.
fn iter_mut_from<T>(slice: &mut [T], k: usize) -> impl Iterator<Item=&mut T> {
// todo
}
One might think that we can simply replace & with &mut and iter with iter_mut like this:
fn iter_mut_from<T>(slice: &mut [T], k: usize) -> impl Iterator<Item=&mut T> {
slice[k..].iter_mut().chain(slice[..k].iter_mut())
}
However, this won’t work. The compiler will complain about multiple mutable borrows of the same slice: (playground link)
error[E0499]: cannot borrow `*slice` as mutable more than once at a time
--> src/main.rs:2:31
|
1 | fn iter_mut_from<T>(slice: &mut [T], k: usize) -> impl Iterator<Item=&mut T> {
| - let's call the lifetime of this reference `'1`
2 | slice[k..].iter_mut().chain(slice[..k].iter_mut())
| ----------------------------^^^^^-----------------
| | |
| | second mutable borrow occurs here
| first mutable borrow occurs here
| returning this value requires that `*slice` is borrowed for `'1`
error[E0308]: mismatched types
--> src/main.rs:7:26
|
7 | for i in iter_mut_from(&array, 5) {
| ------------- ^^^^^^ types differ in mutability
| |
| arguments to this function are incorrect
|
= note: expected mutable reference `&mut [_]`
found reference `&[{integer}; 10]`
note: function defined here
--> src/main.rs:1:4
|
1 | fn iter_mut_from<T>(slice: &mut [T], k: usize) -> impl Iterator<Item=&mut T> {
| ^^^^^^^^^^^^^ ---------------
This is because we are asking for mutable borrow of the same slice twice, one for slice[k..] and another for slice[..k]. We know that these two are mutually exclusive, but the compiler is not that smart enough yet. In order to explicitly tell the compiler we are splitting the slice into two mutually exclusive sub-slices at index k, we need to use a built-in method split_at_mut(), which splits the slice and returns mutable borrow for each side (Rust doc):
pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T])
Now, we can implement our iter_mut_from() method (playground link)
fn iter_mut_from<T>(slice: &mut [T], k: usize) -> impl Iterator<Item=&mut T> {
let (s1, s2) = slice.split_at_mut(k);
s2.iter_mut().chain(s1.iter_mut())
}
In conclusion, we have learned how to create custom iterators in Rust that start from a given index and loop back to the beginning. We have used the chain() and split_at_mut() methods to achieve this functionality. We have also seen how to write both immutable and mutable variants of our iterators. Iterators are powerful tools for writing elegant and efficient code in Rust. How do you use them in your projects? Do you have any questions or suggestions? Share your thoughts in the comment!