He mirado esta pregunta pero todavía no entiendo la diferencia entre los rasgos Iterable y Traversable. ¿Alguien puede explicarlo?
He mirado esta pregunta pero todavía no entiendo la diferencia entre los rasgos Iterable y Traversable. ¿Alguien puede explicarlo?
Respuestas:
En pocas palabras, los iteradores mantienen el estado, los transitables no.
Una Traversable
tiene un método abstracto: foreach
. Cuando llame foreach
, la colección alimentará a la función pasada con todos los elementos que conserva, uno tras otro.
Por otro lado, an Iterable
tiene como método abstracto iterator
, que devuelve un Iterator
. Puede llamar next
a un Iterator
para obtener el siguiente elemento en el momento que elija. Hasta que lo haga, debe realizar un seguimiento de dónde estaba en la colección y qué sigue.
Iterable
extiende Traversable
, así que supongo que te refieres a Traversable
s que no son Iterable
s.
Traversable
interfaz no requiere mantener el estado, mientras que cumplir con la Iterator
interfaz sí.
Traversable
s que Iterable
no mantienen ningún estado de iteración. Es lo Iterator
creado y devuelto por el Iterable
que mantiene el estado.
Piense en ello como la diferencia entre soplar y chupar.
Cuando haya llamado a Traversable
s foreach
, o sus métodos derivados, soplará sus valores en su función uno a la vez, por lo que tiene control sobre la iteración.
Con el Iterator
devuelto por un Iterable
sin embargo, succiona los valores de él, controlando cuándo pasar al siguiente usted mismo.
tl; dr Iterables
son Traversables
que pueden producir statefulIterators
Primero, sepa que Iterable
es un sustrato de Traversable
.
Segundo,
Traversable
requiere implementar el foreach
método, que es utilizado por todo lo demás.
Iterable
requiere implementar el iterator
método, que es utilizado por todo lo demás.
Por ejemplo, la implementación de find
for Traversable
usa foreach
(vía a para comprensión) y lanza una BreakControl
excepción 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, la Iterable
resta anula esta implementación y llama find
a Iterator
, que simplemente deja de iterar 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 Traversable
iteración, 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
usando iterator
, pero realmente no puede implementar iterator
usando foreach
.
En resumen, Iterable
proporciona una forma de pausar, reanudar o detener la iteración mediante un stateful Iterator
. Con Traversable
, es todo o nada (sin excepciones para el control de flujo).
La mayoría de las veces no importa y querrá una 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
.
La respuesta de Daniel suena bien. Déjame ver si puedo expresarlo con mis propias palabras.
Entonces, un Iterable puede darle un iterador, que le permite atravesar los elementos uno a la vez (usando next ()), y detenerse y avanzar cuando lo desee. Para hacer eso, el iterador necesita mantener un "puntero" interno a la posición del elemento. Pero un Traversable le brinda el método, foreach, para atravesar todos los elementos a la vez sin detenerse.
Algo como Range (1, 10) necesita tener solo 2 enteros como estado como Traversable. Pero Range (1, 10) como Iterable le brinda un iterador que necesita usar 3 enteros para el estado, uno de los cuales es un índice.
Teniendo en cuenta que Traversable también ofrece foldLeft, foldRight, su foreach necesita atravesar los elementos en un orden fijo y conocido. Por lo tanto, es posible implementar un iterador para un Traversable. Por ejemplo, def iterator = toList.iterator
Traversable
en Scala 2.13 (todavía se mantiene como un alias obsoletoIterable
hasta 2.14)