我已经阅读了
我想我对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)map
,filter
等方式仍然有效吗?
答案 0 :(得分:5)
NoBuilder
存在,以便客户端可以在转换时将Scala视图视为普通集合。这是一个虚拟实现,允许TraversableView
扩展Traversable
并调用map
之类的方法,而不知道集合是视图还是普通集合。
当您在Scala集合上调用map
,flatMap
或scanLeft
(称为 transformer 操作)时,会自动CanBuildFrom
隐式参数解决。 CanBuildFrom
对象是Builder
个对象的抽象工厂。
大多数Scala集合使用Builders
添加+=
元素,并通过调用buidler上的result
生成新集合。例如。给定构建器对象b
,map
执行此操作:
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)