Scala: What is the difference between Traversable and Iterable traits in Scala collections?

I reviewed this question , but still do not understand the difference between Iterable and Traversable. Can someone explain?

+90
scala scala-collections
Sep 15 2018-11-11T00:
source share
4 answers

Simply put, iterators keep state, workarounds do not.

A Traversable has one abstract method: foreach . When you call foreach , the collection will pass the passed function to all the elements that it stores, one after the other.

On the other hand, Iterable has an abstract iterator method that returns an iterator . You can call next on iterator to get the next item during your selection. While you do this, he should keep track of where he is in the collection, and what's next.

+112
Sep 15 '11 at 3:10
source share

Think of it as the difference between blowing and sucking.

When you call Traversable foreach or its derived methods, it will beat its values ​​in your function one at a time - therefore it has control over the iteration.

With Iterator returned by Iterable , although you are sucking values ​​out of it, controlling when to move on to the next.

+217
Sep 15 '11 at 7:12
source share

tl; dr Iterables are Traversables that stateful Iterators can create.




First, be aware that Iterable is a Traversable subtraction.

Secondly,

  • Traversable requires the use of the foreach method, which is used by everyone else.

  • Iterable requires the use of the iterator method, which is used by everyone else.

For example, to implement find for Traversable , foreach used (through a for understanding) and throws a BreakControl exception to stop the iteration after a satisfactory element is found.

 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 } } 

Unlike subtraction, Iterable overrides this implementation and calls find on iterator , which simply stops the iteration after finding the element:

 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 } } 

It would be nice to not throw exceptions for the Traversable iteration, but this is the only way to partially iterate using only foreach .

On the one hand, Iterable is a more demanding / powerful feature, since you can easily implement foreach with iterator , but you cannot implement iterator with foreach .




Thus, Iterable provides a way to pause, resume, or stop an iteration through a stateful iterator . With Traversable all of this or nothing (no exceptions for flow control).

In most cases, this does not matter, and you need a more general interface. But if you need more individual control over the iteration, you will need an iterator , which you can get from Iterable .

+20
Oct 04 '15 at 22:32
source share

Danielle answer sounds good. Let me see if I can put it in my own words.

This way, Iterable can give you an iterator that allows you to go through the elements one at a time (using next ()), and also stop and go as you like. To do this, the iterator needs to save the internal "pointer" to the position of the element. But Traversable gives you a foreach method to traverse all elements at once without stopping.

Something like Range (1, 10) should only have 2 integers as the state for Traversable. But Range (1, 10) as iterable gives you an iterator that should use 3 integers for the state, one of which is an index.

Given that Traversable also offers foldLeft, foldRight, its foreach should traverse elements in a known and fixed order. Therefore, it is possible to implement an iterator for Traversable. For example, def iterator = toList.iterator

0
Jun 06 '19 at 22:38
source share



All Articles