How does scala.collection.TraversableView.NoBuilder work?

I read

I think I have a little pen on canBuildFrom .

But then I look at the source for the TraversableView , and I see this:

 object TraversableView { class NoBuilder[A] extends Builder[A, Nothing] { def +=(elem: A): this.type = this def iterator: Iterator[A] = Iterator.empty def result() = throw new UnsupportedOperationException("TraversableView.Builder.result") def clear() {} } type Coll = TraversableView[_, C] forSome {type C <: Traversable[_]} implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, TraversableView[A, Traversable[_]]] = new CanBuildFrom[Coll, A, TraversableView[A, Traversable[_]]] { def apply(from: Coll) = new NoBuilder def apply() = new NoBuilder } } 

How does TraversableView work like this? Nothing seems to be happening here ( NoBuilder seems aptly named).

Can someone explain (1) the function that NoBuilder plays here, and (2) like map , filter , etc. can still work?

+6
source share
1 answer

NoBuilder exists so that customers can view Scala views as if they were regular collections when they were transformed. This is a dummy implementation that allows TraversableView to extend Traversable and call methods like map , without knowing if the collection is a view or a regular collection.

Longer explanation

When you call map , flatMap or scanLeft (called transformer operations) in the Scala collection, the implicit CanBuildFrom argument CanBuildFrom automatically resolved. The CanBuildFrom object is an abstract factory object for the Builder .

Most Scala collections use Builders to add items using += and create a new collection by calling result on the buidler. For instance. The given constructor b , map does the following:

 def map[S, That](f: T => S)(implicit cbf: CanBuildFrom[Repr, S, That]) = { val b: Builder[S, That] = cbf(this) for (x <- this) b += f(x) b.result } 

Transformation operations in views do not create a new collection. Instead, they create a lazy performance. For example, map does something like this:

 def map[S, That](f: T => S)(implicit cbf: CanBuildFrom[Repr, S, That]) = new TraversableView { def foreach[U](forFunc: T => U): Unit = for (x <- self) forFunc(f(x)) } 

Note that a map in the view has the same signature, but does not actually invoke += and result in the builder. Thus, the NoBuilder used in views does not really need to store items or return a collection, it is just a dummy whose methods are never called.

The same signature allows you to write this in the client code:

 def foo(xs: Traversable[Int]) = xs.map(_ + 1) foo(0 until 100) foo((0 until 100).view) 
+5
source

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


All Articles