加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Scala的mutable.ListBuffer似乎使用了List的尾部函数,但它被记录

发布时间:2020-12-16 18:21:29 所属栏目:安全 来源:网络整理
导读:从 scala的2.12.8 current documentation开始,List的尾部是常量,ListBuffer的尾部是线性的.但是,查看 source code,看起来尾部函数没有覆盖,并且在大多数用例中(例如删除head元素),List的尾部函数被显式调用.由于ListBuffer似乎只是一个带有长度var和指向最后
从 scala的2.12.8 current documentation开始,List的尾部是常量,ListBuffer的尾部是线性的.但是,查看 source code,看起来尾部函数没有覆盖,并且在大多数用例中(例如删除head元素),List的尾部函数被显式调用.由于ListBuffer似乎只是一个带有长度var和指向最后一个元素的指针的List包装器,为什么它是线性的?

我对两种方法进行了计时,看起来List的尾部是常量,而ListBuffer的尾部确实是线性的:

import scala.collection.mutable
import scala.collection.immutable

val immutableList: immutable.List[Int] = (1 to 10000).toList
val mutableListBuffer: mutable.ListBuffer[Int] = mutable.ListBuffer.empty[Int] ++= (1 to 10000).toList

// Warm-up
(1 to 100000).foreach(_ => immutableList.tail)
(1 to 100000).foreach(_ => mutableListBuffer.tail)

// Measure
val start = System.nanoTime()
(1 to 1000).foreach(_ => immutableList.tail)
val middle = System.nanoTime()
(1 to 1000).foreach(_ => mutableListBuffer.tail)
val stop = System.nanoTime()

println((middle - start) / 1000)
println((stop - middle) / 1000)

结果如:

1076
86010

但是,如果使用诸如remove(0)之类的函数使用List的尾部,则它是常量,具有以下结果:

1350
1724

我希望线性复杂性来自构建一个全新的列表返回,但由于内部结构是一个List,为什么不返回List的尾部呢?

解决方法

ListBuffer不扩展List,并且它不覆盖tail的事实并不意味着它使用List#tail.如果你看一下 tail on ListBuffer文档的定义类部分,你会看到它来自TraversableLike,它的定义如下:

override def tail: Repr = {
  if (isEmpty) throw new UnsupportedOperationException("empty.tail")
  drop(1)
}

如果你看一下drop,你会发现它使用一个构建器来构造一个包含除第一个元素之外的所有元素的新集合,这解释了为什么它是线性的.

正如talex在上面的注释中暗示的那样,ListBuffer#tail必须返回一个新的集合,因为原始缓冲区可以被修改,标准库设计者已经决定你不希望那些修改反映在你从尾部获得的结果中.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读