concatenate - scala mutable collections
Scala: ¿Cuál es la diferencia entre los rasgos de Traversable y Iterable en las colecciones de Scala? (3)
Para decirlo simplemente, los iteradores mantienen el estado, los traversables no.
Un Traversable
tiene un método abstracto: foreach
. Cuando llame a foreach
, la colección transmitirá a la función pasada todos los elementos que mantiene, uno después del otro.
Por otro lado, un iterator
tiene como iterator
método abstracto, que devuelve un Iterator
. Puede llamar a next
en un Iterator
para obtener el siguiente elemento en el momento que elija. Hasta que lo haga, debe hacer un seguimiento de dónde estaba en la colección y qué es lo próximo.
He analizado esta pregunta pero todavía no entiendo la diferencia entre los rasgos Iterable y Traversable. ¿Alguien puede explicar?
Piense en ello como la diferencia entre soplar y chupar.
Cuando llame a un Traversable
foreach
Traversable
, o sus métodos derivados, inflará sus valores en su función de uno en uno, para que tenga control sobre la iteración.
Sin embargo, con el Iterator
devuelto por un Iterable
, le quitas los valores, controlando cuándo pasar al siguiente tú mismo.
tl; dr Iterables
son Traversables
que pueden producir Iterators
estado
Primero, sepa que Iterable
es un atributo de Traversable
.
Segundo,
Traversable
requiere implementar el métodoforeach
, que es utilizado por todo lo demás.Iterable
requiere implementar el método deiterator
, que es utilizado por todo lo demás.
Por ejemplo, la implementación de find
para Traversable
usa foreach
(a través de a para comprensión) y arroja una excepción BreakControl
para detener la iteración una vez que se ha encontrado un elemento satisfactorio.
trait TravserableLike {
def find(p: A => Boolean): Option[A] = {
var result: Option[A] = None
breakable {
for (x <- this)
if (p(x)) { result = Some(x); break }
}
result
}
}
Por el contrario, el resta Iterable
anula esta implementación y llama a find
en el Iterator
, que simplemente detiene la iteración una vez que se encuentra el elemento:
trait Iterable {
override /*TraversableLike*/ def find(p: A => Boolean): Option[A] =
iterator.find(p)
}
trait Iterator {
def find(p: A => Boolean): Option[A] = {
var res: Option[A] = None
while (res.isEmpty && hasNext) {
val e = next()
if (p(e)) res = Some(e)
}
res
}
}
Sería bueno no lanzar excepciones para la iteración de Traversable
, pero esa es la única forma de iterar parcialmente cuando se usa solo foreach
.
Desde una perspectiva, Iterable
es el rasgo más exigente / poderoso, ya que puede implementar fácilmente foreach
utilizando iterator
, pero no puede implementar iterator
utilizando foreach
.
En resumen, Iterable
proporciona una forma de pausar, reanudar o detener la iteración a través de un Iterator
estado. Con Traversable
, es todo o nada (sin excepciones para el control de flujo).
La mayoría de las veces no importa, y querrás la interfaz más general. Pero si alguna vez necesita un control más personalizado sobre la iteración, necesitará un Iterator
, que puede recuperar de un Iterable
.