scala.collection.TraversableView.NoBuilder如何工作?

时间:2014-06-28 01:23:28

标签: scala collections

我已经阅读了

我想我对canBuildFrom有一点处理。

然后我查看了TraversableView的来源,我看到了这一点:

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

TraversableView如何像这样工作?似乎这里没有任何事情发生(NoBuilder似乎恰当地命名)。

有人可以解释(1)NoBuilder在这里播放的功能以及(2)mapfilter等方式仍然有效吗?

1 个答案:

答案 0 :(得分:5)

NoBuilder存在,以便客户端可以在转换时将Scala视图视为普通集合。这是一个虚拟实现,允许TraversableView扩展Traversable并调用map之类的方法,而不知道集合是视图还是普通集合。

更长的解释

当您在Scala集合上调用mapflatMapscanLeft(称为 transformer 操作)时,会自动CanBuildFrom隐式参数解决。 CanBuildFrom对象是Builder个对象的抽象工厂。

大多数Scala集合使用Builders添加+=元素,并通过调用buidler上的result生成新集合。例如。给定构建器对象bmap执行此操作:

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
}

视图上的Transformer操作不会实例化新集合。相反,他们创造了一个懒惰的视图。例如,map执行以下操作:

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

请注意,视图上的map具有相同的签名,但实际上并未在构建器上调用+=result。因此,视图中使用的NoBuilder实际上并不需要存储元素或返回集合,它只是一个虚拟的方法永远不会被调用。

相同的签名允许在客户端代码中写入:

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