scala iterator

scala - ¿Cuál es la relación entre Iterable e Iterator?



(2)

¿Cuál es la diferencia entre Iterator e Iterable en scala?

Pensé que Iterable representa un conjunto que puedo repetir, y Iterator es un "puntero" para uno de los elementos en el conjunto iterable.

Sin embargo, Iterator tiene funciones como para cada forEach , map , foldLeft . Se puede convertir a Iterable través de Iterable . Y, por ejemplo, scala.io.Source.getLines devuelve scala.io.Source.getLines , no Iterable .

Pero no puedo hacer groupBy en groupBy y puedo hacerlo en Iterable .

Entonces, ¿cuál es la relación entre esos dos, Iterator e Iterable ?


En resumen: un Iterator tiene estado, mientras que un Iterator no.

Ver los documentos API para ambos.

Iterable :

Un rasgo base para colecciones iterables.

Este es un rasgo básico para todas las colecciones de Scala que definen un método iterador para recorrer paso por paso los elementos de la colección. [...] Este rasgo implementa el método foreach de Iterable al recorrer todos los elementos usando el iterador.

Iterator :

Iteradores son estructuras de datos que permiten iterar sobre una secuencia de elementos. Tienen un método hasNext para verificar si hay un próximo elemento disponible, y un siguiente método que devuelve el siguiente elemento y lo descarta del iterador.

Un iterador es mutable: la mayoría de las operaciones en él cambian su estado. Si bien a menudo se utiliza para recorrer los elementos de una colección, también se puede usar sin tener el respaldo de ninguna colección (ver constructores en el objeto complementario).

Con un Iterator puede detener una iteración y continuarla más tarde si lo desea. Si intenta hacer esto con un Iterable , comenzará desde la cabeza otra vez:

scala> val iterable: Iterable[Int] = 1 to 4 iterable: Iterable[Int] = Range(1, 2, 3, 4) scala> iterable.take(2) res8: Iterable[Int] = Range(1, 2) scala> iterable.take(2) res9: Iterable[Int] = Range(1, 2) scala> val iterator = iterable.iterator iterator: Iterator[Int] = non-empty iterator scala> if (iterator.hasNext) iterator.next res23: AnyVal = 1 scala> if (iterator.hasNext) iterator.next res24: AnyVal = 2 scala> if (iterator.hasNext) iterator.next res25: AnyVal = 3 scala> if (iterator.hasNext) iterator.next res26: AnyVal = 4 scala> if (iterator.hasNext) iterator.next res27: AnyVal = ()

Tenga en cuenta que no Iterator take on Iterator . La razón de esto es que es difícil de usar. hasNext y el next son los únicos dos métodos que están garantizados para funcionar como se espera en Iterator . Ver el Iterator nuevo:

Es de particular importancia señalar que, a menos que se indique lo contrario, nunca se debe usar un iterador después de llamar a un método en él. Las dos excepciones más importantes son también los únicos métodos abstractos: next y hasNext.

Ambos métodos se pueden llamar cualquier cantidad de veces sin tener que descartar el iterador. Tenga en cuenta que incluso hasNext puede causar mutación, como al iterar desde una secuencia de entrada, donde se bloqueará hasta que se cierre la secuencia o cuando haya alguna entrada disponible.

Considere este ejemplo para un uso seguro e inseguro:

def f[A](it: Iterator[A]) = { if (it.hasNext) { // Safe to reuse "it" after "hasNext" it.next // Safe to reuse "it" after "next" val remainder = it.drop(2) // it is *not* safe to use "it" again after this line! remainder.take(2) // it is *not* safe to use "remainder" after this line! } else it }


Otra explicación de Martin Odersky y Lex Spoon:

Hay una diferencia importante entre el método foreach en los iteradores y el mismo método en las colecciones rastreables: cuando se llama a un iterador, foreach dejará el iterador al final cuando termine. Así que volver a llamar nuevamente en el mismo iterador fallará con una NoSuchElementException. Por el contrario, cuando se invoca en una colección, foreach deja la cantidad de elementos en la colección sin cambios (a menos que la función pasada se agregue para eliminar elementos, pero esto se desaconseja, ya que puede llevar a resultados sorprendentes).

Fuente: http://www.scala-lang.org/docu/files/collections-api/collections_43.html

Tenga en cuenta también (gracias a Wei-Ching Lin por este consejo) Iterator amplía el rasgo TraversableOnce mientras que Iterable no lo hace.