通過List.apply方法構造List的背後邏輯

通過List伴生對象的apply方法來創建實例: List("A","B") 過程發生了什麼

首先,List伴生對象的apply方法接收的是一個可變參數列表,即數組:

override def apply[A](xs: A*): List[A] = xs.toList

而我們傳入的Array("A","B")數組會被隱式轉換爲 WrappedArray 的子類型,這是在LowPriorityImplicits裏定義的:

// Since the JVM thinks arrays are covariant, one 0-length Array[AnyRef]
// is as good as another for all T <: AnyRef.  Instead of creating 100,000,000
// unique ones by way of this implicit, let's share one.

implicit def wrapRefArray[T <: AnyRef](xs: Array[T]): WrappedArray[T] = {
    if (xs eq null) null
    else if (xs.length == 0) WrappedArray.empty[T]
    else new WrappedArray.ofRef[T](xs)
}

隨後對這個WrappedArray 的子類型ofRef[String]類型,調用 toList 方法

不過在進行toList時用到了隱式參數CanBuildFrom,我們先看一下List伴生對象中定義的,用於生成CanBuildFrom信息的隱式方法:

/** $genericCanBuildFromInfo */
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, List[A]] =
    ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]]

現在來追蹤toList的執行過程,在父類TraversableOncetoList方法裏調用了to方法,而這個to方法裏有聲明一個隱式參數。

用隱式參數CanBuildFrom構造了一個List類型的容器,把數據填充進去,再返回result

裏面的隱式參數:

implicit cbf: CanBuildFrom[Nothing, A, Col[A @uV]] 

先不用管裏面難懂的類型參數,編譯在尋找對應的隱式參數值時,通過上面的 to[List]聲明的目標類型是List,所以從List的伴生對象中去尋找,通過 canBuildFrom隱式函數得到了需要的參數,它是把一個可複用的對象造型成我們需要的CBF類型:

ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]]

ReusableCBF的意思是可複用的CanBuildFrom,它在 GenTraversableFactory裏定義:

通過這個CBF隱式參數幫我們構造了一個新的容器,然後把當前集合裏的數據放進去,最後再調用新容器的result來得到List

通過斷點,發現 b.result 時進入了 ListBuffer.toList 的代碼裏,也就是說這個隱式參數構造出來的新容器類型是 ListBuffer 的子類型。

最終,它返回ListBuffer類裏的start成員,這個start是一個 :: 類型(List的子類)

發佈了35 篇原創文章 · 獲贊 58 · 訪問量 27萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章