#015 Apr 2022

15. Scan

Iterator adapter similar to fold (see previous bite) - holds some internal state and produces new iterator.

Note that Option is yielded from the closure.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
let nums = [1, 2, 3];

let mut iter = nums.iter().scan(0, |acc, &x| {
    *acc = *acc + x;
    Some((*acc, x))
});

assert_eq!(iter.next(), Some((1, 1)));
assert_eq!(iter.next(), Some((3, 2)));
assert_eq!(iter.next(), Some((6, 3)));
#014 Apr 2022

14. Find index of item

Use position to find position of an element in iterator. Returns None if the element does not exist.

1
2
3
4
5
6
let nums = [1, 2, 3];

let pos = nums.iter().position(|value| *value == 3);
assert_eq!(pos, Some(2));
let pos = nums.iter().position(|value| *value == 10);
assert_eq!(pos, None);
#017 Mar 2022

17. filter_map

Similar to map but if allows to drop an item.

1
2
3
4
5
6
7
8
let text_nums = ["1", "two", "three", "4"];

let nums: Vec<_> = text_nums
    .iter()
    .filter_map(|x| x.parse::<u32>().ok())
    .collect();

assert_eq!(nums, vec![1, 4]);
#013 Mar 2022

13. Fold

Iterator consumer. Allows the accumulated value to be arbitrary type. Note the different types.

1
2
3
let nums: Vec<u8> = vec![1, 2, 3, 4];
let sum = nums.iter().fold(0u32, |acc, x| acc + *x as u32);
assert_eq!(sum, 10);
#012 Mar 2022

12. Enumerate

Use enumerate to convert iterator over (usize,item) pairs.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
let cars = vec!["Skoda", "Ferrari", "Ford"];

for (idx, car) in cars.iter().enumerate() {
    println!("{idx} - {car}");
}

// Output
// 0 - Skoda
// 1 - Ferrari
// 2 - Ford

Useful when index of item is needed.

#011 Mar 2022

11. Fuse

Fuse is an iterator that yields None forever after the underlying iterator yields None once. USage:

1
2
let values = [1,2,3,4];
let iter = values.iter().fuse();

Why is it useful? see example in this bite.

Sometimes an underlying iterator may or may yield Some(T) again after None was returned.

fuse ensures that after a None is returned for the first time, it always returns None.

Example from the rust documentation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
struct Alternate {
    state: i32,
}

impl Iterator for Alternate {
    type Item = i32;

    fn next(&mut self) -> Option<i32> {
        let val = self.state;
        self.state = self.state + 1;

        if val % 2 == 0 {
            Some(val)
        } else {
            None
        }
    }
}

let mut iter = Alternate { state: 0 };

assert_eq!(iter.next(), Some(0));
assert_eq!(iter.next(), None);
assert_eq!(iter.next(), Some(2));
assert_eq!(iter.next(), None);

let mut iter = iter.fuse();

assert_eq!(iter.next(), Some(4));
assert_eq!(iter.next(), None);

assert_eq!(iter.next(), None);
assert_eq!(iter.next(), None);
assert_eq!(iter.next(), None);
#010 Feb 2022

10. cloned vs copied

Rust provides built-in methods to copy or clone elements when using an iterator.

Eg.

1
let nums: Vec<u32> = nums1.iter().chain(&nums2).copied().collect();

What’s the difference? and when is it useful?

You may have done something like this:

1
let nums: Vec<u32> = nums1.iter().chain(&nums2).map(|x| *x).collect();

but instead, use copied.

1
let nums: Vec<u32> = nums1.iter().chain(&nums2).copied().collect();

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
let nums = vec![1,2,3,4];
let nums2 = vec![5,6,7,8];

// doiing it manually by copying
// let all_nums: Vec<u32> = nums.iter().chain(&nums2).map(|x| *x).collect();

// doiing it manually by cloneing
// let all_nums: Vec<u32> = nums.iter().chain(&nums2).map(|x| x.clone()).collect();

// but why not just use provided functionality ??!
let all_nums: Vec<u32> = nums.iter().chain(&nums2).copied().collect();

// or cloned if copy it is not an option
//let all_nums: Vec<u32> = nums.iter().chain(&nums2).cloned().collect();

 assert_eq!(all_nums, vec![1,2,3,4,5,6,7,8]);

Difference between cloned and copied?

Same reasoning aplies as for Copy and Clone traits. Use copied to avoid to accidentally cloing iterator elements. Use copied when possible.

#009 Feb 2022

9. Inspecting iterator

Ever wondered how to print while iterating?

Use inspect.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
let cars = vec!["Skoda", "Ferrari", "Ford"];

let car_lenghts: Vec<u32> = cars
    .iter()
    .enumerate()
    .inspect(|(idx, s)| println!("{idx} - {s}"))
    .map(|(_, name)| name.len() as u32)
    .collect();

assert!( car_lenghts == vec![5,7,4
#008 Feb 2022

8. Drain

Use drain to remove specified range from a vector.

1
2
3
4
5
let mut a = vec![1,2,3,4,5];

let _ = a.drain(0..3);

assert!(a == vec![4,5]);

What is the difference to call into_iter which returns T ?

into_iter takes the collection by value and consumes it.

drain borrows mutable reference, and returns a drain iterator of elements. If such iterator is dropped without exhausting it, all elements are dropped.

#007 Feb 2022

7. iter() vs into_iter()

What is the difference between .iter() and .into_iter()?

iter yields &T

into_iter may yield any of T, &T or &mut T based on context.

1
2
3
4
5
6
7
8
9
let cars = vec!["Skoda", "Ferrari", "Ford"];

for car in cars.iter() {
    println!("{car}");
}

for car in cars.into_iter() {
    println!("{car}");
}

this works but …

This does not. This results in compile error because cars are moved due to into_iter call.

1
2
3
4
5
6
7
8
9
let cars = vec!["Skoda", "Ferrari", "Ford"];

for car in cars.into_iter() {
  println!("{car}");
}

for car in cars.iter() {
    println!("{car}");
}