初学者';关于+;=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)
}。