第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之后就尽量不要再修改元素。
本讲主要讲解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之后就尽量不要再修改元素。
相关文章推荐
- 学习英语经验
- C++之运算符重载
- Android Studio优化
- CentOS 7 virt-manager 无法连接本地的hypervisor
- 安全删除STL容器元素
- request.getParameterValues与request.getParameter的区别
- TypeError:e is undefined
- request.getParameterValues与request.getParameter的区别
- (转)JAVA的整型与字符串相互转换
- MySQL 数据库ut8mb4字符集
- iOS-Core Animation 核心动画
- linux之sed用法
- hdu 1010 Tempter of the Bone(搜索+奇偶剪枝)
- 火星菌
- 简单的心搏函数
- HDU - 1232 - 畅通工程
- Linux 网卡驱动学习(六)(应用层、tcp 层、ip 层、设备层和驱动层作用解析)
- 机器学习之实战matlab神经网络工具箱
- ArrayList中的toArray()
- 2015第33周二