How do I work with Scala collections in general?

I realized that my typical way of passing Scala collections around might use some improvement.

def doSomethingCool(theFoos: List[Foo]) = { /* insert cool stuff here */ } // if I happen to have a List doSomethingCool(theFoos) // but elsewhere I may have a Vector, Set, Option, ... doSomethingCool(theFoos.toList) 

I prefer to write my library functions to take List as a parameter type, but I'm sure there is something more general that I can do there to avoid all the random .toList calls that I have in the application code. This especially annoying since my doSomethingCool function usually requires calling map , flatMap and filter , which are defined for all types of collections.

What are my options for this “something more general”?

+4
source share
2 answers

Here are more general features, each of which extends the previous one:

  • GenTraversableOnce
  • GenTraversable
  • GenIterable
  • GenSeq

The above lines do not indicate whether the collection is sequential or parallel. If your code requires that everything be executed sequentially (usually if your code has side effects of any type), they are too general for it.

The following features ensure consistent execution:

  • TraversableOnce
  • Traversable
  • Iterable
  • Seq
  • LinearSeq

First, TraversableOnce only allows one method to be called in a collection. After that, the collection was "used." In return, this is common enough to accept iterators as well as collections.

Traversable is a fairly general set that most methods have. There are some things that he cannot do, however, in this case you need to go to Iterable .

All Iterable implements an iterator method that allows you to get an iterator for this collection. This makes it possible for several methods not present in Traversable .

A Seq[A] implements the function Int => A , which means that you can access any element by its index. This does not guarantee effectiveness, but it is a guarantee that each element has an index, and that you can make statements about what this index will be. Contrast this with Map and Set , where you cannot determine what the index of an element is.

A LinearSeq is a Seq that provides fast head , tail , isEmpty and prepend. This is as close to List as possible without actually using List explicitly.

Alternatively, you can have IndexedSeq which has fast indexed access (something List doesn't provide).

See also this question and this FAQ based on this.

+6
source

The most obvious is the use of Traversable as the most common feature that will have the right product. However, I think you tend to stick with it better:

  • Seq
  • IndexedSeq
  • Set
  • Map

A Seq will cover List , Vector , etc., IndexedSeq will cover Vector , etc. etc. I didn’t use Iterable because I often (or need) to know the size of what I have, and pre scala -2.8 Iterable didn’t provide access to it , so I had to turn things into sequences anyway!

It looks like Traversable and Iterable now have size methods, so maybe I should return to using them! Of course, you can start to “go crazy” with GenTraversableOnce , but this is unlikely to help in readability.

+4
source

Source: https://habr.com/ru/post/1387582/


All Articles