【发布时间】:2018-03-21 02:58:01
【问题描述】:
我试图了解 Listbuffer 是如何实现的。
@SerialVersionUID(3419063961353022662L)
final class ListBuffer[A]
extends AbstractBuffer[A]
with Buffer[A]
with GenericTraversableTemplate[A, ListBuffer]
with BufferLike[A, ListBuffer[A]]
with ReusableBuilder[A, List[A]]
with SeqForwarder[A]
with Serializable
{
override def companion: GenericCompanion[ListBuffer] = ListBuffer
import scala.collection.Traversable
import scala.collection.immutable.ListSerializeEnd
/** Expected invariants:
* If start.isEmpty, last0 == null
* If start.nonEmpty, last0 != null
* If len == 0, start.isEmpty
* If len > 0, start.nonEmpty
*/
private var start: List[A] = Nil
private var last0: ::[A] = _
private var exported: Boolean = false
private var len = 0
...
}
第一个问题是,我无法理解 private var last0 的语法 ::[A] = _。虽然它看起来像一个类型,但 ::[A] 是什么意思,为什么它需要 RHS 上的 _?看起来语法是用来表示List的最后一个元素的,但是它是怎么工作的呢?
第二个问题与 ListBuffer 使用 Var 尾部而不是 Val 尾部(即使它是不可变的)来加快加法速度有关。 上面的 += 函数如何帮助它实现更快的加法???
def += (x: A): this.type = {
if (exported) copy()
if (isEmpty) {
last0 = new :: (x, Nil)
start = last0
} else {
val last1 = last0
last0 = new :: (x, Nil)
last1.tl = last0
}
len += 1
this
}
最后一个问题是关于 ListBuffer 的添加是如何工作的。在空的 ListBuffer 被第一个元素填充之后, start 似乎一直指向 last0 ,并且 start 在它再次变为空之前不会改变。而在第一个之后的添加,将列表的尾部更改为由以下代码行创建的新列表。
val last1 = last0
last0 = new :: (x, Nil)
last1.tl = last0
看起来原始列表last0的尾部被更改为包含x的新last0,但似乎这段代码并没有真正扩展开头指向的列表。它是如何工作的..?似乎将 last0 分配给 last1.tl 会将 List(x) 附加到 start 指向的 List 中,但我不明白它是如何工作的。
如果可能,您能否解释一下 start、last0、last1 将如何随着输入序列 += 1、+= 2、+= 3 等发生变化?
【问题讨论】:
-
::is a class 是一种类型。 -
@jwvh,谢谢!那么作业的 RHS 中的“_”是什么意思?
-
RHS
_用于将var初始化为默认值。默认值根据其类型确定。Int的默认值为0。::实例的默认值为null。这只是many uses of the underscore 的又一个例子。 -
@jwvh。啊哈!谢谢,那么 += 操作在 ListBuffer 中是如何工作的?似乎 += 操作从 new ::(x, Nil) 创建了一个新的 List(x) 并将其分配给 start 指向的 List 的 tl 。似乎 last1.tl 只是一个 var List[T] 并且永远不会将新元素附加到 start 指向的 List 中。
-
您在这里有大约 5 个问题。如果你有 5 个问题,请提出 5 个问题,而不是填塞然后变成一个。特别是,因为您的大部分问题已经在Stack Overflow 上被多次询问和回答,因此重复出现是题外话。
标签: scala