ListBuffer
可以有效地将元素附加到其末尾,然后转换为List
。
我研究了ListBuffer
附加方法(+=
)的源代码,但发现很难理解其工作原理。详细的源代码是here。
摘录源代码:
final class ListBuffer[A] extends AbstractBuffer[A] {
private var start: List[A] = Nil
private var last0: ::[A] = _
private var exported: Boolean = false
private var len = 0
def += (x: A): this.type = {
if (exported) copy()
if (isEmpty) {
last0 = new :: (x, Nil)
start = last0
} else {
val last1 = last0 // last1 is a local variable, is it necessary here?
last0 = new :: (x, Nil)
last1.tl = last0 //
}
len += 1
this
}
}
在else
部分中,定义了局部变量last1
,然后构造为在末尾包含多个元素。 last0
始终指向最后一个单元格。
这里需要last1
吗?毕竟,阻塞之后它将超出范围。我不明白为什么作者必须在这里定义last1
。
答案 0 :(得分:2)
那么,
val last1 = last0 // last1 is a local variable, is it necessary here?
last0 = new :: (x, Nil)
last1.tl = last0 //
正如您所看到的,在我们已经更改.tl
之后,它确实用于更改last0
。
那时.tl
是什么?
@SerialVersionUID(509929039250432923L) // value computed by serialver for 2.11.2, annotation added in 2.11.4
final case class ::[B](override val head: B, private[scala] var tl: List[B]) extends List[B] {
override def tail : List[B] = tl
override def isEmpty: Boolean = false
}
正如您所看到的,类::
并不是真正不可变的:对列表的其余部分有一个可以更改的引用,这正是最后一行所做的。
现在为什么在更改last0
后需要更改?那是因为我们需要一个临时变量来保留新创建的最后一个元素,我们需要将last0
分配给该元素 - 所以我们只需重新分配last0
并一次创建新的最后一个元素,并在之后链接旧的最后一个元素(在last1
中保存)。
希望它有所帮助。
答案 1 :(得分:1)
这里发生的事情基本上是
last0.ti = new :: (x, Nil) // put new element x at end of list
除了这种减少有问题:last0
总是需要“指向”结束。因此last1
成为对列表末尾的临时引用,以便可以访问end-of-the-list.t1
并添加新的列表结尾。
答案 2 :(得分:0)
所以有3行。
last1将指向当前的last0。
last0设置为新的最后一个元素。
last1.t1设置为last0。
last1不是新对象。它只是指向当前的最后一个。 t1我假设是指向其下一个元素的类指针。 那么它的作用是将当前的最后一个元素指向新元素。
这在scala中可能会造成混淆,因为它使用了scala中可以避免的mutable和vars。