Home
rustbites
Cancel

18. flatten options

Use flatten to iterate over only Some values if you have a collection of Options.

1
2
3
4
5
6
let nums = vec![None, Some(2), None, Some(3), None];

let mut iter = nums.into_iter().flatten();

assert_eq!(iter.next(), Some(2));
assert_eq!(iter.next(), Some(3));

16. Option/Result match?!

Try to avoid matching Option or Result.

Use if let instead.

1
2
3
4
5
6
7
8
9
10
11
12
13
let result = Some(111);

// Not nice
match result {
    Some(x) => println!("{x}"),
    None => {}
};

// Better
if let Some(x) = result {
    println!("{x}");
}

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)));

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);

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]);

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);

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.

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.

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?

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