J'ai regardé cette question mais je ne comprends toujours pas la différence entre les traits Iterable et Traversable. Quelqu'un peut-il expliquer?
J'ai regardé cette question mais je ne comprends toujours pas la différence entre les traits Iterable et Traversable. Quelqu'un peut-il expliquer?
Réponses:
Pour faire simple, les itérateurs conservent l'état, les traversables non.
A Traversable
a une méthode abstraite: foreach
. Lorsque vous appelez foreach
, la collection alimentera la fonction passée tous les éléments qu'elle conserve, l'un après l'autre.
D'autre part, an Iterable
a comme méthode abstraite iterator
, qui retourne un Iterator
. Vous pouvez faire appel next
à un Iterator
pour obtenir l'élément suivant au moment de votre choix. Jusqu'à ce que vous le fassiez, il doit garder une trace de l'endroit où il se trouvait dans la collection et de la suite.
Iterable
s'étend Traversable
, donc je suppose que vous voulez dire Traversable
s qui ne sont pas Iterable
s.
Traversable
interface ne nécessite pas de garder l'état, alors que se conformer à l' Iterator
interface le fait.
Traversable
Les s qui Iterable
ne conservent aucun état d'itération. C'est le Iterator
créé et retourné par le Iterable
qui garde l'état.
Pensez-y comme la différence entre souffler et sucer.
Lorsque vous appelez un Traversable
s foreach
, ou ses méthodes dérivées, il insuffle ses valeurs dans votre fonction une à la fois - il a donc le contrôle sur l'itération.
Avec le Iterator
retourné par un Iterable
cependant, vous en aspirez les valeurs, en contrôlant vous-même le moment de passer à la suivante.
tl; dr Iterables
sont Traversables
qui peuvent produire avec étatIterators
Premièrement, sachez que Iterable
c'est un sous-portrait de Traversable
.
Seconde,
Traversable
nécessite l'implémentation de la foreach
méthode, qui est utilisée par tout le reste.
Iterable
nécessite l'implémentation de la iterator
méthode, qui est utilisée par tout le reste.
Par exemple, l'implémentation de find
for Traversable
uses foreach
(via un for comprehension) et lève une BreakControl
exception pour arrêter l'itération une fois qu'un élément satisfaisant a été trouvé.
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
}
}
En revanche, la Iterable
soustraction remplace cette implémentation et appelle find
le Iterator
, qui arrête simplement d'itérer une fois l'élément trouvé:
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
}
}
Ce serait bien de ne pas lancer d'exceptions pour l' Traversable
itération, mais c'est la seule façon d'itérer partiellement en utilisant juste foreach
.
D'un point de vue, Iterable
c'est le trait le plus exigeant / puissant, car vous pouvez facilement implémenter l' foreach
utilisation iterator
, mais vous ne pouvez pas vraiment implémenter l' iterator
utilisation foreach
.
En résumé, Iterable
fournit un moyen de suspendre, de reprendre ou d'arrêter l'itération via un état Iterator
. Avec Traversable
, c'est tout ou rien (sans exceptions pour le contrôle de flux).
La plupart du temps, cela n'a pas d'importance et vous voudrez une interface plus générale. Mais si jamais vous avez besoin d'un contrôle plus personnalisé sur l'itération, vous aurez besoin d'un Iterator
, que vous pouvez récupérer à partir d'un fichier Iterable
.
La réponse de Daniel sonne bien. Voyons si je peux le dire avec mes propres mots.
Ainsi, un Iterable peut vous donner un itérateur, qui vous permet de parcourir les éléments un à la fois (en utilisant next ()), et de s'arrêter et de partir à votre guise. Pour ce faire, l'itérateur doit garder un "pointeur" interne sur la position de l'élément. Mais un Traversable vous donne la méthode, foreach, pour traverser tous les éléments à la fois sans s'arrêter.
Quelque chose comme Range (1, 10) n'a besoin que de 2 entiers comme état comme Traversable. Mais Range (1, 10) en tant que Iterable vous donne un itérateur qui doit utiliser 3 entiers pour l'état, dont l'un est un index.
Considérant que Traversable propose également foldLeft, foldRight, son foreach doit traverser les éléments dans un ordre connu et fixe. Il est donc possible d'implémenter un itérateur pour un Traversable. Par exemple, def iterator = toList.iterator
Traversable
dans Scala 2.13 (il est toujours conservé comme alias obsolèteIterable
jusqu'à 2.14)