您的位置:首页 > 其它

第83讲:Scala中List的实现内幕源码揭秘学习笔记

2015-08-11 21:57 447 查看
第83讲:Scala中List的实现内幕源码揭秘学习笔记
本讲主要讲解List实现的具体内部的关键源码
上讲讲了listbuffer对list的高效遍历,解决了堆栈溢出的问题和使用遍历时的效率问题
scala中的list在后来的版本中都采用了这种方法。

toList不会低效,ListBuffer最后 一个元素是List的最后一个元素,

/*Converts this buffer to a list.Takes constant time. The buffer is
copied lazily, the first time it is mutated.*/
override def toList: List[A] = {
exported = !start.isEmppty
start //只是返回start,基本不耗时间。start指向元素列表
}

//Listd take(n:Int)源码:
override def take(n:Int):List[A]={
val b = new ListBuffer[A]
var i= 0
var these = this
while(!these.isEmpty && i<n){
i += 1
b += these.tail
}
if(these.isEmpty) this
else b.toList
}
/*这里构建了一个高效的ListBuffer的实例b,
最后将实例b通过b.toList方法变成List.
toList方法的源代码如下:
override def toList:List[A]={
exported = !start.isEmpty
start
}
这里ListBuffer返回的是其第一个元素,所以ListBuffer的toList是一个高效的方法。
toList不会复制存储在ListBuffer中的列表,只是返回,所以效率很高。

final case class ::[B](private var hd: B,private[scala] var tl: List[B] extends List[B]){
//默认情况下List都是不可变元素。
//private[scala] var tl可以看出,外部不可修改tl,只有在scala包中才能修改。
//往列表中增加元素时内部都是利用ListBuffer方式去做的。
override def head : B = hd
override def tail : List[B] = tl
override def isEmpty: Bollean = false

private def readObject(in: ObjectInputStream){
val firstObject = in.readObject()
hd = firstObject.asInstanceOf[B]
assert(hd != ListSerializeEnd)
var current: ::[B] = this
while (true) in.readObject match {
case ListSerializeEnd =>
current.tl = Nil
return
case a =>
val list : ::[B] = new ::(a.asInstanceOf[B],Nil)
current.tl = list
current = this
}
}
private def writeObject(out: ObjectOutputStream){
var xs:List[B] = this
while (!xs.isEmpty) { out.writeObject(xs.head);xs = xs.tail}
out.writeObject(ListSerializeEnd)
}
}

往List中追加元素:
def += (x: A): this.type = {
if (exported) copy() //对不变列表操作时,会产生一个新列表
if (start.isEmpty) {
last0 = new :: (x, Nil)
start = last0
} else {
val last1 = last0
last0 = new :: (x, Nil)
last1.t1 = last0
//不断在后面追加元素。
}
len += 1
this

private def copy(){
var cursor = start
val limit = last0.tail
clear()
while (cursor ne limit){
this += cursor.head
cursor = cursor.tail
}
}
//可以看出copy是比较花时间的。
}
exported为ListBuffer中的flag(default:false),
当flag为true时,表明Buffer已进行了toList操作,
此时再进行连接等操作时,会有copy链表的动作发生,
消耗内存,在实际编程中应谨慎。
toList之后就尽量不要再修改元素。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: