Iterators
Links:
- https://doc.rust-lang.org/book/ch13-02-iterators.html
- https://dev.to/martcpp/understanding-map-vs-flatmap-in-rust-with-a-simple-analogy-408g
Итераторы
Итераторы позволяют выполнять действия по очереди над цепочкой данных. Итератор берёт каждый объект цепочки и проверяет, не последний или он. Итераторы в Rust - ленивые, т.е не отрабатывают, пока не будет вызван метод, который их поглощает.
iter()
Возвращает Iterator<Item = &T>, забирает на себя массив без изменений (immutable), поэтому исходный массив далее доступен для других действий. Применять для задач чтения.
into_iter()
Возвращает Iterator<Item = T>, делает move массиву, после применения массив использовать нельзя. Применять для задач изменений с исходным массивом.
Когда ты пишешь for x in коллекция, Rust автоматически вызывает into_iter(), потому что это “по умолчанию” забирает коллекцию. Если хочешь оставить коллекцию, явно используй for x in коллекция.iter().
iter_mut()
Возвращает Iterator<Item = &mut T>, забирает на себя массив с возможностью его менять прямо на месте. Исходный массив далее доступен для других действий.
Цикл for с iter(), into_iter(), iter_mut()
Синтаксический сахар:
| Характеристика | iter | into_iter | iter_mut |
|---|---|---|---|
| Что возвращает | Ссылки (<T>) | Сами значения (T) | Изменяемые ссылки ( <mut T>) |
| Можно ли менять элементы | Нет, только смотреть | Да, но коллекция уже твоя | Да, через ссылки |
| Что с коллекцией | Остаётся живой | “Исчезает” (перемещается) | Остаётся живой |
| Тип итератора | Итератор по ссылкам | Итератор по значениям | Итератор по изменяемым ссылкам |
| Когда использовать | Хочу посмотреть элементы | Хочу забрать элементы | Хочу изменить элементы на месте |
Требуется ли mut для коллекции | Нет | Нет (но коллекция уходит) | Да, коллекция должна быть mut |
| Пример кода | for x in vec.iter() | for x in vec.into_iter() | for x in vec.iter_mut() |
| Пример результата | x — ссылка,vec жив | x — значение,vec мёртв | x — изменяемая ссылка,vec жив |
repeat, repeat_n, take, skip
repeat - создаёт строку, повторяя заданный символ N раз (N as usize).
Например, вывести квадрат из символов “+” размера n (через клонирование):
repeat_n - создаёт итератор, который возвращает заданный элемент N раз (N as usize) без клонирования (в отличие от repeat):
take - возвращает первые N элементов итератора (N as usize), если итератор не исчерпает себя раньше:
take часто используют с бесконечным итератором для задания ему конечного числа итераций:
skip(n) создаёт новый итератор, в котором пропускает заданное число n элементов исходного итератора, а остальные возвращает. С помощью него удобно обрабатывать данные, пропустив заголовок, либо параметры введённой команды с пропуском имени самой команды:
Вместе take() и skip() комбинируются, чтобы получить средние значения в массиве:
Отличие .map() и .flat_map()
Обе функции раскрывают итератор вектора, однако, с разным результатом:
.map() - сохраняет структуру в итоговом результате .flat_map() - убирает лишние структуры
counts()
Считает число объектов в итераторе и возвращает как HashMap.
Заглядывающий (peekable) итератор
peekable() превращает обычный итератор в итератор, который позволяет посмотреть на следующий элемент, не продвигая итератор вперед.
next_if() - взять элемент только если условие выполняется
Пример
Взятие символов в строке так, чтобы разбивать строку на пары из двух символов. Если строка содержит нечетное количество символов, то недостающий второй символ последней пары должен быть заменен на символ подчеркивания (’_’).