为什么我们在Scala List的inits方法中需要中间的newBuilder

时间:2014-03-17 19:33:20

标签: scala

Scala为inits定义了List方法,该方法执行以下操作:

List(1, 2, 3).inits.toList  // List(List(1, 2, 3), List(1, 2), List(1), List())

以这种方式实现:

def inits: Iterator[Repr] = iterateUntilEmpty(_.init)

private def iterateUntilEmpty(f: Traversable[A @uV] => Traversable[A @uV]): Iterator[Repr] = {
  val it = Iterator.iterate(thisCollection)(f) takeWhile (x => !x.isEmpty)
  it ++ Iterator(Nil) map (x => (newBuilder ++= x).result)
}

我掀起了一个不太通用的版本(只是为了玩):

val L = List(1,2,3)
val it = Iterator.iterate(L)(_.init) takeWhile (x => !x.isEmpty)
it ++ Iterator(Nil) map (x => (new ListBuffer ++= x).result) toList
// List(List(1, 2, 3), List(1, 2), List(1), List())

但是在我看来,我们可以不用ListBuffer部分:

val L = List(1,2,3)
val it = Iterator.iterate(L)(_.init) takeWhile (x => !x.isEmpty)
it ++ Iterator(Nil) toList
// List(List(1, 2, 3), List(1, 2), List(1), List())

结果似乎是一样的。

那么为什么库实现使用newBuilder
它对性能有何影响?

1 个答案:

答案 0 :(得分:1)

希望Rex Kerr @ rex-kerr能够启动某种长期工作并检查SO的问题,但在此之前,您已经问过为什么没有列出专门的{{1} }。

我认为两个答案是专门针对每个具体的集合都是一个维护问题,并且重写该方法会与JVM的策略竞争以进行编译。

我想我在消息来源中读到,在性能受到影响之前,JVM将容忍两次这样的调度以覆盖。我不是专家,但直觉是假设一种方法实际上是最终的更有效。

但等一下,您的TraversableLike.inits.toList不一样。

你的问题减少了,为什么不完全为List留下建设者,因为你从迭代器获得了列表。

好吧,也许它不适用于其他类型:

.map(_.toList)