初学者';关于+;=Scala中ListBuffer类的方法

初学者';关于+;=Scala中ListBuffer类的方法,scala,Scala,ListBuffer可以有效地将元素附加到其末尾,然后转换为列表 我研究了ListBuffer的append方法(+=)的源代码,但发现很难理解它的工作原理。详细的源代码如下所示 摘录的源代码: final class ListBuffer[A] extends AbstractBuffer[A] { private var start: List[A] = Nil private var last0: ::[A] = _ private var exported: Boolean

ListBuffer
可以有效地将元素附加到其末尾,然后转换为
列表

我研究了
ListBuffer
的append方法(
+=
)的源代码,但发现很难理解它的工作原理。详细的源代码如下所示

摘录的源代码:

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

这里发生的事情本质上是

last0.ti = new :: (x, Nil)  // put new element x at end of list
除了此减少有一个问题:
last0
始终需要“指向”结尾。因此,
last1
成为列表末尾的临时引用,这样就可以访问列表末尾。t1并可以添加列表的新结尾。

因此有3行

last1将指向当前last0

last0设置为新的最后一个元素

last1.t1设置为last0

last1不是新对象。它只是指向当前的最后一个。 我假设t1是指向下一个元素的类指针。 因此,它所做的是将当前的最后一个元素指向新元素

这在scala中可能会令人困惑,因为它使用了可变项和变量,如果可能的话,在scala中可以避免使用这些可变项和变量

  val last1 = last0     // last1 is a local variable, is it necessary here?
  last0 = new :: (x, Nil)
  last1.tl = last0      // 
如您所见,在我们更改
last0
之后,它确实用于更改
.tl

那么,
.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


希望有帮助。

谢谢。仍然令人困惑。为什么“我们需要一个临时变量来保存新创建的最后一个元素”
last0=new::(x,Nil)
将最后一个单元格存储在
last0
的类字段中。但是
last1
只是一个局部变量,它在
else
代码块之后消失。仅仅移动
last0
是不够的;您还需要倒数第二个元素的
tl
指向刚刚创建的元素。所以
last0.tl=new::(x,Nil);last0=last0.tl
就可以了,用
tl
代替
last1
。两者之间的选择取决于味道和/或性能测试。我发现
+=
方法的这个实现有一些问题。附加的元素无法保存到
start
列表中。下面是一个执行演示:(1)
valt=newlistbuffer[Int]
;(2)
t+=1
/{
start=List(1)
last0=List(1)
};(3)
t+=2
;{
start=List(1)
last0=List(1)
}(4)
t.toList
{
List(1)
}。