Пользовательские итераторы
Реализация Iterator
«Пользовательские итераторы» — бесплатный урок Learn Rust Coding на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Learn Rust Coding, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Learn Rust Coding содержит 4 уроков всего.
Создаём собственный итератор
Вы не ограничены встроенными итераторами. Реализовав трейт Iterator для собственного типа, Вы бесплатно получаете все адаптеры и потребители.
Нужно предоставить только тип Item и метод next.
Структура Counter
Начните со структуры, хранящей состояние итератора. Простому счётчику достаточно текущего значения.
struct Counter {
count: u32,
}
fn main() {
let c = Counter { count: 0 };
println!("start at {}", c.count);
}Реализация next
Реализуйте Iterator для структуры. Задайте type Item, затем напишите next, чтобы изменять состояние и возвращать Some до наступления условия остановки, а затем None.
struct Counter { count: u32 }
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.count < 5 {
self.count += 1;
Some(self.count)
} else {
None
}
}
}
fn main() {
let mut c = Counter { count: 0 };
println!("{:?}", c.next());
println!("{:?}", c.next());
}Использование в цикле for
Как только появляется next, Ваш тип работает в цикле for так же, как любой стандартный итератор.
struct Counter { count: u32 }
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.count < 5 { self.count += 1; Some(self.count) } else { None }
}
}
fn main() {
for n in (Counter { count: 0 }) {
print!("{} ", n);
}
println!();
}Бесплатные адаптеры и потребители
Поскольку Вы реализовали один метод, теперь доступен весь набор инструментов итераторов. Здесь мы суммируем квадраты парных значений счётчика.
struct Counter { count: u32 }
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.count < 5 { self.count += 1; Some(self.count) } else { None }
}
}
fn main() {
let total: u32 = Counter { count: 0 }.map(|x| x * 2).sum();
println!("{}", total);
}Метод-конструктор
Добавьте функцию new, чтобы пользователям не приходилось обращаться к внутренним полям напрямую. Это чище и позволяет оставить поле закрытым.
struct Counter { count: u32 }
impl Counter {
fn new() -> Counter { Counter { count: 0 } }
}
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.count < 3 { self.count += 1; Some(self.count) } else { None }
}
}
fn main() {
let v: Vec<u32> = Counter::new().collect();
println!("{:?}", v);
}Итератор Фибоначчи
Итераторы могут хранить более сложное состояние. Генератор Фибоначчи хранит два последних значения и обновляет их при каждом вызове next.
struct Fib { a: u64, b: u64 }
impl Iterator for Fib {
type Item = u64;
fn next(&mut self) -> Option<u64> {
let current = self.a;
self.a = self.b;
self.b = current + self.b;
Some(current)
}
}
fn main() {
let fib = Fib { a: 0, b: 1 };
let seq: Vec<u64> = fib.take(8).collect();
println!("{:?}", seq);
}Бесконечные итераторы — это нормально
Итератор Фибоначчи никогда не возвращает None — он бесконечен. Это безопасно, потому что благодаря ленивости значения создаются только по запросу. Используйте take, чтобы ограничить последовательность.
struct Fib { a: u64, b: u64 }
impl Iterator for Fib {
type Item = u64;
fn next(&mut self) -> Option<u64> {
let c = self.a;
self.a = self.b;
self.b = c + self.b;
Some(c)
}
}
fn main() {
let big = Fib { a: 0, b: 1 }.nth(20);
println!("{:?}", big);
}Итерация по типу-обёртке
Часто реализацию Iterator добавляют для вспомогательной структуры, которая заимствует ваши данные. Здесь пошаговый итератор выдаёт каждое второе число из хранящегося внутри диапазона.
struct EvenUpTo { current: u32, max: u32 }
impl Iterator for EvenUpTo {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.current > self.max { return None; }
let value = self.current;
self.current += 2;
Some(value)
}
}
fn main() {
let evens: Vec<u32> = (EvenUpTo { current: 0, max: 10 }).collect();
println!("{:?}", evens);
}Зачем создавать собственные итераторы
Собственные итераторы позволяют передавать значения потоком без выделения памяти под всю коллекцию, моделировать бесконечные или вычисляемые последовательности и предоставлять вызывающему коду знакомый, композиционный интерфейс.
Один небольшой метод next открывает доступ ко всей экосистеме.
Советы по проектированию
Храните минимум состояния, возвращайте None ровно один раз в конце (а для бесконечных итераторов — никогда) и избегайте трудоёмких операций внутри next, чтобы ленивые вычисления оставались дешёвыми.
Быстрая проверка
Реализация признака Iterator.
Итоги
Вы создали собственные итераторы:
- Храните состояние в структуре, затем используйте
impl Iterator - Определите
type Itemи напишитеnext - Сразу бесплатно получаете адаптеры и потребители
- Итераторы могут быть конечными или бесконечными; используйте
take, чтобы ограничить бесконечные
Часто задаваемые вопросы
Урок «Пользовательские итераторы» бесплатный?
Да — полный текст урока «Пользовательские итераторы» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Learn Rust Coding, подпишись на CoddyKit PRO. Курс Learn Rust Coding содержит 4 уроков всего.
Чему я научусь в уроке «Пользовательские итераторы»?
Реализация Iterator Ты практикуешь Learn Rust Coding с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Learn Rust Coding?
Предыдущий опыт не требуется. Learn Rust Coding на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Пользовательские итераторы»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Learn Rust Coding?
Да. Каждый урок Learn Rust Coding включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Трейт Iterator
- map, filter, collect
- Адаптеры и потребители
- Пользовательские итераторы