Итераторы
Что такое итератор в Rust?
Итератор в Rust — это трейт (
std::iter::Iterator).
Трейт Iterator:
#![allow(unused)] fn main() { pub trait Iterator { type Item; fn next(&mut self) -> Option<Self::Item>; // ... множество предоставляемых методов по умолчанию } }
Создание итераторов:
1. Из коллекций (реализуют трейт IntoIterator):
#![allow(unused)] fn main() { let vec = vec![1, 2, 3]; let iter = vec.iter(); // Итератор по &T let iter_mut = vec.iter_mut(); // Итератор по &mut T let into_iter = vec.into_iter(); // Итератор, потребляющий коллекцию (T) }
2. Диапазоны:
#![allow(unused)] fn main() { let range = 1..10; // 1 до 9 let range_inclusive = 1..=10; // 1 до 10 }
3. Адаптеры итераторов:
#![allow(unused)] fn main() { let mapped = vec.iter().map(|x| x * 2); let filtered = vec.iter().filter(|x| *x % 2 == 0); }
4. Создание кастомных итераторов:
#![allow(unused)] fn main() { struct Counter { count: u32, } impl Iterator for Counter { type Item = u32; fn next(&mut self) -> Option<Self::Item> { if self.count < 5 { self.count += 1; Some(self.count) } else { None } } } }
Организация в памяти:
Размер на стеке:
- Итераторы обычно имеют фиксированный размер во время компиляции
- Не требуют heap-аллокации (если не содержат
Boxи т.д.) - Пример:
#![allow(unused)] fn main() { let iter = vec![1, 2, 3].into_iter(); // Размер известен компилятору, хранится на стеке }
Типы итераторов:
- By-reference:
iter()→std::slice::Iter<'a, T> - By-mutable-reference:
iter_mut()→std::slice::IterMut<'a, T> - By-value:
into_iter()→std::vec::IntoIter<T>
Потребители итераторов:
1. Явное использование next():
#![allow(unused)] fn main() { let mut iter = vec![1, 2, 3].iter(); while let Some(item) = iter.next() { println!("{}", item); } }
2. Цикл for (синтаксический сахар):
#![allow(unused)] fn main() { for item in vec.iter() { println!("{}", item); // Автоматически вызывает next() } }
3. Методы-потребители:
#![allow(unused)] fn main() { let sum: i32 = vec.iter().sum(); // Потребляет итератор let collected: Vec<_> = iter.collect(); // Потребляет итератор let count = iter.count(); // Потребляет итератор }
4. Адаптеры (ленивые, не потребляют сразу):
#![allow(unused)] fn main() { let result: Vec<_> = vec![1, 2, 3] .iter() .map(|x| x * 2) // Ленивый - не выполняется до потребления .filter(|x| x > &2) // Ленивый .collect(); // Потребляет, форсирует вычисления }
Ключевые особенности:
Ленивость:
#![allow(unused)] fn main() { let iter = vec![1, 2, 3].iter().map(|x| { println!("Processing: {}", x); x * 2 }); // Ничего не напечатано - вычисления не начались let result: Vec<_> = iter.collect(); // Теперь вычисления выполнены }
Zero-cost abstractions:
- Итераторы компилируются в эффективный код
- Часто сопоставим с ручным циклом по производительности
Типовая система:
#![allow(unused)] fn main() { fn process<I: Iterator<Item = i32>>(iter: I) { for item in iter { println!("{}", item); } } }
Итератор в Rust — это трейт, который предоставляет поток элементов, с ленивыми вычислениями и эффективной компиляцией в оптимальный машинный код.