Scala可以使用不同的Map实例化不同大小的Map实例。结果,
val l = List("a", "b", "c", "d", "e", "f", "g")
val ms = l.zipWithIndex map {
case (e, i) => l.take(i).zipWithIndex.toMap /// toMap
}
ms.foreach(m => println(m.getClass))
会发出:
class scala.collection.immutable.Map$EmptyMap$
class scala.collection.immutable.Map$Map1
class scala.collection.immutable.Map$Map2
class scala.collection.immutable.Map$Map3
class scala.collection.immutable.Map$Map4
class scala.collection.immutable.HashMap$HashTrieMap
class scala.collection.immutable.HashMap$HashTrieMap
(上面的代码由toMap
生成,但使用apply
非常相似。)
我发现toMap
被定义为
def toMap[T, U](implicit ev: A <:< (T, U)): immutable.Map[T, U] = {
val b = immutable.Map.newBuilder[T, U]
for (x <- self)
b += x
b.result()
}
魔术部分将是result()
的{{1}},因为它最终确定应该实例化哪个Map子类。
在Builder
内,有object Map
,EmptyMap
,Map1
,Map2
,Map3
和Map4
是object HashMap
;另外,两者都包含隐式HashTrieMap
。
那么Scala编译器如何确定将哪个子类用于Map?
(此问题可能更多关于MapCanBuildFrom
,例如,CanBuildFrom
会实例化Seq(1)
。)
答案 0 :(得分:6)
我在scala库中偷看,似乎对Map的这4个特定impl的唯一引用是在他们自己的“更新”和“ - ”方法中。 魔术从方法newBuilder中的MutableMapFactory开始,其中调用Map.empty来生成EmptyMap类。 然后调用更新并添加键和值将使其成为Map1。然后再次调用Map1中的更新方法可以导致Map1或Map2,并且调用 - 方法可以导致EmptyMap。等...
y