Ответ 1
Первый вопрос: "Что такое into_iter
?"
into_iter
происходит от черты IntoIterator
:
pub trait IntoIterator where <Self::IntoIter as Iterator>::Item == Self::Item, { type Item; type IntoIter: Iterator; fn into_iter(self) -> Self::IntoIter; }
Вы реализуете эту особенность, когда хотите указать, как конкретный тип должен быть преобразован в итератор. В частности, если тип реализует IntoIterator
, его можно использовать в цикле for
.
Например, Vec
реализует IntoIterator
... трижды!
impl<T> IntoIterator for Vec<T> impl<'a, T> IntoIterator for &'a Vec<T> impl<'a, T> IntoIterator for &'a mut Vec<T>
Каждый вариант немного отличается.
Этот использует Vec
и его итератор возвращает значения (непосредственно T
):
impl<T> IntoIterator for Vec<T> { type Item = T; type IntoIter = IntoIter<T>; fn into_iter(mut self) -> IntoIter<T> { /* ... */ } }
Два других берут вектор по ссылке (не дайте себя одурачить сигнатурой into_iter(self)
, потому что self
является ссылкой в обоих случаях), и их итераторы будут создавать ссылки на элементы внутри Vec
.
Этот дает неизменные ссылки:
impl<'a, T> IntoIterator for &'a Vec<T> { type Item = &'a T; type IntoIter = slice::Iter<'a, T>; fn into_iter(self) -> slice::Iter<'a, T> { /* ... */ } }
В то время как этот дает изменяемые ссылки:
impl<'a, T> IntoIterator for &'a mut Vec<T> { type Item = &'a mut T; type IntoIter = slice::IterMut<'a, T>; fn into_iter(self) -> slice::IterMut<'a, T> { /* ... */ } }
Итак:
В чем разница между
iter
иinto_iter
?
into_iter
- это универсальный метод для получения итератора, независимо от того, выдает ли этот итератор значения, неизменяемые или изменяемые ссылки , зависит от контекста и иногда может вызывать удивление.
iter
и iter_mut
являются специальными методами. Это работает вокруг контекстно-зависимого бита и, по соглашению, позволяет вам получить итератор, который будет выдавать ссылки.
Автор поста "Rust by Example" иллюстрирует удивление, вызванное зависимостью от контекста (то есть типа), из которого вызывается into_iter
, а также усугубляет проблему, используя тот факт, что:
IntoIterator
не реализован для[T; N]
, только для&[T; N]
и&mut [T; N]
- Когда метод не реализован для значения, вместо него автоматически выполняется поиск ссылок на это значение
что очень удивительно для into_iter
, поскольку все типы (кроме [T; N]
) реализуют его для всех 3 вариантов (значение и ссылки). Массив не может реализовать итератор, который выдает значения, потому что он не может "сжаться", чтобы отказаться от своих элементов.
Относительно того, почему массивы реализуют IntoIterator
(таким удивительным образом): это позволяет делать итерации по ссылкам на них в циклах for
.