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,
Traversablerequiere implementar el métodoforeach, que es utilizado por todo lo demás.Iterablerequiere 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 .