Итератор против IntoIterator для сглаживания
Я играю с итераторами и использую их, Flattenчтобы лучше понять, как работают итераторы. Этот пример:
assert_eq!(vec![1, 2].iter().flatten().count(), 2);
Не компилируется и выдает ошибку (ну, это основная ошибка, вызывающая беспокойство):
error[E0277]: `&{integer}` is not an iterator
--> src/lib.rs:59:38
|
59 | assert_eq!(vec![1, 2].iter().flatten().count(), 2);
| ^^^^^^^ `&{integer}` is not an iterator
|
= help: the trait `std::iter::Iterator` is not implemented for `&{integer}`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&{integer}`
Что меня смущает, так это то, что, похоже, для реализации Flattenтребуется вложенное . Я подтвердил это в rustdocs, где они заявляютItemIntoIterator
pub struct Flatten<I>
where
I: Iterator,
<I as Iterator>::Item: IntoIterator
На момент подготовки документации IntoIterator просто предоставляет способ определить, как тип преобразуется в итератор. Почему нельзя было привязать черту <I as Iterator>::Item: Iterator? Конечно, если вложенный элемент реализует Iterator, то мы получим то же самое, Flattenпоскольку вложенные элементы сами должны быть итераторами. Какую разницу / пользу он приносит IntoIteratorвместо этого?
Ответы
Требование, IntoIteratorа не Iteratorпозволяет сгладить коллекцию коллекций в дополнение к коллекции итераторов.
Тип коллекции, например Vec, отличается от типа итератора, поэтому, если flattenтребуется, чтобы элементы были Iterators, вы не могли бы сгладить a Vecof Vecs.
IntoIteratorпредставляет тип, который можно преобразовать в итератор, такой как Vecколлекция или многие другие (или итератор!). Так, например, работает:
fn main() {
let nested_vec: Vec<Vec<i32>> = vec![vec![1, 2], vec![3, 4]];
let flat_vec: Vec<i32> = nested_vec.into_iter().flatten().collect();
println!("{:?}", flat_vec);
}
Вы можете попробовать этот пример на игровой площадке . Использование into_iter()выше вместо iter()гарантирует, что мы перебираем i32s, а не ссылки на i32s. (Спасибо Cerberus за предложение into_iter()вместо copied().)
(Вы можете увидеть еще несколько типов с IntoIteratorреализациями в разделе документации «Реализации для внешних типов» .)