Трейт Iterator
Трейт Iterator определяет, как объект можно использовать для получения последовательности значений. Например, если мы хотим создать итератор, который выдаёт элементы среза, это может выглядеть примерно так:
// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
struct SliceIter<'s> {
slice: &'s [i32],
i: usize,
}
impl<'s> Iterator for SliceIter<'s> {
type Item = &'s i32;
fn next(&mut self) -> Option<Self::Item> {
if self.i == self.slice.len() {
None
} else {
let next = &self.slice[self.i];
self.i += 1;
Some(next)
}
}
}
fn main() {
let slice = &[2, 4, 6, 8];
let iter = SliceIter { slice, i: 0 };
for elem in iter {
dbg!(elem);
}
}
-
Пример
SliceIterреализует ту же логику, что и циклforв стиле C из предыдущего слайда. -
Укажите студентам, что итераторы ленивы: создание итератора лишь инициализирует структуру, а никакой работы не выполняет. Работа начинается только при вызове метода
next. -
Итераторы не обязаны быть конечными! Вполне допустим итератор, который будет выдавать значения бесконечно. Например, полуоткрытый диапазон вроде
0..будет продолжаться, пока не произойдёт переполнение целого.
Для дальнейшего изучения
-
«Настоящая» версия
SliceIter— это типslice::Iterиз стандартной библиотеки, но настоящая версия использует под капотом указатели вместо индекса, чтобы исключить проверки границ. -
Пример
SliceIterхорошо показывает структуру, которая содержит ссылку, и поэтому использует аннотации времён жизни. -
Также можно показать, как добавить обобщённый параметр в
SliceIter, чтобы он работал с любым срезом (а не только с&[i32]).