通過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
的執行過程,在父類TraversableOnce
的toList
方法裏調用了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的子類)