Подтвердить что ты не робот

В чем разница между iter и in_iter?

Я делаю Rust by Example, в котором есть этот фрагмент кода:

// Vec example
let vec1 = vec![1, 2, 3];
let vec2 = vec![4, 5, 6];

// `iter()` for vecs yields `&i32`. Destructure to `i32`.
println!("2 in vec1: {}", vec1.iter()     .any(|&x| x == 2));
// `into_iter()` for vecs yields `i32`. No destructuring required.
println!("2 in vec2: {}", vec2.into_iter().any(| x| x == 2));

// Array example
let array1 = [1, 2, 3];
let array2 = [4, 5, 6];

// `iter()` for arrays yields `&i32`.
println!("2 in array1: {}", array1.iter()     .any(|&x| x == 2));
// `into_iter()` for arrays unusually yields `&i32`.
println!("2 in array2: {}", array2.into_iter().any(|&x| x == 2));

Я полностью смущен - для a Vec итератор, возвращенный из iter, возвращает ссылки, и итератор, возвращаемый из into_iter, дает значения, но для массива эти итераторы идентичны?

Что такое использование /API для этих двух методов?

4b9b3361

Ответ 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, а также усугубляет проблему, используя тот факт, что:

  1. IntoIterator не реализован для [T; N], только для &[T; N] и &mut [T; N]
  2. Когда метод не реализован для значения, вместо него автоматически выполняется поиск ссылок на это значение

что очень удивительно для into_iter, поскольку все типы (кроме [T; N]) реализуют его для всех 3 вариантов (значение и ссылки). Массив не может реализовать итератор, который выдает значения, потому что он не может "сжаться", чтобы отказаться от своих элементов.

Относительно того, почему массивы реализуют IntoIterator (таким удивительным образом): это позволяет делать итерации по ссылкам на них в циклах for.

Ответ 2

.into_iter() не реализован для самого массива, а только &[]. Для сравнения:

impl<'a, T> IntoIterator for &'a [T]
    type Item = &'a T

с

impl<T> IntoIterator for Vec<T>
    type Item = T

Так как IntoIterator определяется только на &[T], сам срез нельзя отбросить так же, как Vec, когда вы используете значения. (значения не могут быть перемещены)

Теперь, почему это случай - это разные проблемы, и я хотел бы узнать себя. Спекуляция: массив - это сами данные, срез - это только представление. На практике вы не можете переместить массив как значение в другую функцию, просто передайте его, поэтому вы также не можете его использовать.

Ответ 3

Я (новичок Rust) пришел сюда из Google в поисках простого ответа, который не был предоставлен другими ответами. Вот этот простой ответ:

  • iter() перебирает элементы по ссылке
  • into_iter() перебирает элементы, перемещая их в новую область видимости
  • iter_mut() перебирает элементы, давая изменяемую ссылку на каждый элемент

Таким образом, for x in my_vec { ... } по существу эквивалентен my_vec.into_iter().for_each(|x| ... ) - оба move элемента my_vec входят в область действия ....

Если вам просто нужно "посмотреть" на данные, используйте iter, если вам нужно отредактировать/изменить их, используйте iter_mut, а если вам нужно предоставить нового владельца, используйте into_iter.

Это было полезно: http://hermanradtke.com/2015/06/22/effectively-using-iterators-in-rust.html

Сделать это вики-сообществом, чтобы, надеюсь, профессионал Rust мог редактировать этот ответ, если я допустил какие-либо ошибки.