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

来源:互联网 发布:qq加人软件 编辑:程序博客网 时间:2024/06/07 06:30

83讲:ScalaList的实现内幕源码揭秘学习笔记

本讲主要讲解List实现的具体内部的关键源码

上讲讲了listbufferlist的高效遍历,解决了堆栈溢出的问题和使用遍历时的效率问题

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返回的是其第一个元素,所以ListBuffertoList是一个高效的方法。

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是比较花时间的。

}

exportedListBuffer中的flagdefault:false),

flagtrue时,表明Buffer已进行了toList操作,

此时再进行连接等操作时,会有copy链表的动作发生,

消耗内存,在实际编程中应谨慎。

toList之后就尽量不要再修改元素。

0 0
原创粉丝点击