第83講:Scala中List的實現內幕原始碼揭祕
阿新 • • 發佈:2019-02-03
本講視訊是王家林老師通過認真解讀scala原始碼的方式講解了《Scala中List的實現內幕原始碼揭祕》。本講內容如下:
ListBuffer(連結串列快取)相當於List的一個工具類,List本身繼承ListBuffer,擁有ListBuffer中非私有的方法。對List的操作其實有部分是通過ListBuffer完成的。exported為LiftBuffer中flag(default:false),當flag為true時,表明Buffer已進行了toList操作,此時再進行連線等操作時,會有copy連結串列的動作發生,消耗記憶體,在實際程式設計中應謹慎。
scala的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是一個高效的方法。
List的子類::的原始碼如下:
final case class ::[B](private var hd:B,private[scala] var tl:List[B])extends List[B]{....}
這裡第二個引數tl是除了第一個引數之外所構成的一個List,修飾符private[scala]表示只有scala包下的物件才能訪問,所以ListBuffer可以訪問第二個引數tl。
ListBuffer的原始碼如下:
private var start:List[A] = Nil
private var last0: ::[A]=_
private exported:Boolean = false
private var len = 0
這裡的start指向了儲存快取的所有列表,預設值是Nil.
ListBuffer的toList方法的原始碼如下:
override def toList:List[A]={
exported = !start.isEmpty
start
}
所以toList不會複製儲存ListBuffer裡面的列表,他只負責返回第一個元素,所以toList的效率非常高。
ListBuffer的追加元素的方法+=的原始碼如下:
def +=(x:A): this.type = {
if(exported)copy()
.....
}
這說明如果ListBuffer變成了List的時候我們就把它複製一份,這就產生了一個新的列表。