rust

rust - ¿Cuál es la diferencia entre iter e into_iter?



(2)

La primera pregunta es: "¿Qué es into_iter ?"

into_iter proviene del rasgo IntoIterator :

pub trait IntoIterator where <Self::IntoIter as Iterator>::Item == Self::Item, { type Item; type IntoIter: Iterator; fn into_iter(self) -> Self::IntoIter; }

Implementa este rasgo cuando desea especificar cómo se convertirá un tipo particular en un iterador. En particular, si un tipo implementa IntoIterator , puede usarse en un bucle for .

Por ejemplo, Vec implementa IntoIterator ... ¡tres veces!

impl<T> IntoIterator for Vec<T> impl<''a, T> IntoIterator for &''a Vec<T> impl<''a, T> IntoIterator for &''a mut Vec<T>

Cada variante es ligeramente diferente.

Este consume el Vec y su iterador produce valores ( T directamente):

impl<T> IntoIterator for Vec<T> { type Item = T; type IntoIter = IntoIter<T>; fn into_iter(mut self) -> IntoIter<T> { /* ... */ } }

Los otros dos toman el vector por referencia (no se deje engañar por la firma de into_iter(self) porque self es una referencia en ambos casos) y sus iteradores producirán referencias a los elementos dentro de Vec .

Este produce referencias inmutables :

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> { /* ... */ } }

Si bien este produce referencias mutables :

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> { /* ... */ } }

Asi que:

¿Cuál es la diferencia entre iter e into_iter ?

into_iter es un método genérico para obtener un iterador, ya sea que este iterador produzca valores, referencias inmutables o referencias mutables depende del contexto y a veces puede ser sorprendente.

iter e iter_mut son métodos ad-hoc. Esto funciona alrededor del bit dependiente del contexto y, por convención, le permite obtener un iterador que producirá referencias.

El autor de la publicación Rust by Example ilustra la sorpresa que viene de la dependencia del contexto (es decir, el tipo) en el que se llama into_iter , y también agrava el problema al usar el hecho de que:

  1. IntoIterator no está implementado para [T; N] [T; N] , solo para &[T; N] &[T; N] y &mut [T; N] &mut [T; N]
  2. Cuando un método no se implementa para un valor, se busca automáticamente referencias a ese valor

lo cual es muy sorprendente para into_iter ya que todos los tipos (excepto [T; N] ) lo implementan para las 3 variaciones (valor y referencias). No es posible que la matriz implemente un iterador que arroje valores porque no puede "reducir" para renunciar a sus elementos.

En cuanto a por qué los arreglos implementan IntoIterator (de una manera tan sorprendente): es para hacer posible iterar sobre las referencias a ellos en bucles.

Estoy haciendo el tutorial Rust by Example que tiene este fragmento de código:

// 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));

Estoy completamente confundido: para un Vec el iterador devuelto por iter produce referencias y el iterador devuelto por into_iter produce valores, pero para una matriz, estos iteradores son idénticos.

¿Cuál es el caso de uso / API para estos dos métodos?


.into_iter() no está implementado para una matriz en sí, sino solo &[] . Comparar:

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

con

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

Dado que IntoIterator se define solo en &[T] , el segmento en sí no se puede descartar de la misma manera que Vec cuando utiliza los valores. (los valores no se pueden mover)

Ahora, por qué ese es el caso es un problema diferente, y me gustaría aprender yo mismo. Especulando: la matriz es la información en sí misma, el segmento es solo una vista. En la práctica, no puede mover la matriz como valor a otra función, simplemente pasar una vista de ella, por lo que tampoco puede consumirla allí.