Kotlin地图:为什么没有toHashMap()?

在Kotlin中, Map类有toLinkedMap()toSortedMap()扩展方法。

但为什么没有toHashMap()方法? 实际上,许多stdlib方法的Map实现是LinkedHashMap ,但是在我的代码中将其转换为HashMap会使我依赖于不好的实现。

引入这样的方法会使开发人员无法深入实现,而在目前的实现中,它只是执行演员。

我的用例是:

 val matchesInClass: HashMap<MessageClass, HashMap<Int, Int>> //... for ((cl, matches) in matchesInClass) { matchesInClass[cl] = matches.filterKeys { it !in banned } //error: not a HashMap } 

当我使用HashMap(matches.filterKeys { it !in banned }) ,会导致创建一个新地图的开销,我很乐意避免。

那么,是由设计?

我同意在stdlib这个地方是不方便的。 但是你怎么想要这样一个函数来实现toHashMap()呢?

如果底层映射是HashMap,那么最简单的实现就是HashMap,否则就进行转换。 因此,在更改实现的情况下,该代码的性能将发生显着变化。 那很糟。

所以,恕我直言,我更喜欢不安全的演员,如果stdlib以一种奇怪的方式变化,并提醒我这个失败。

无论如何,你总是欢迎在YouTrack http://youtrack.jetbrains.com/issues/KT作为票证报告这个问题&#x3002; 你对这个问题做了一个很好的描述,所以不用多久。

为什么? 很难回答,但是为Kotlin问题跟踪器搜索或添加票据将会得到您的答案,并在状态更改时更新您的答案。 它似乎没有toHashMap丢失,因为toHashSet在那里(1.0 BETA 4)。

注意: LinkedHashMap是默认的,因为kotlin在从ListSetListMapList过程中想要维护元素的顺序,并确保事物仍然处于相对顺序。

无论如何,与此同时,这里是一个为您定制的toHashMap

 public fun <K, V> Iterable<Pair<K, V>>.toHashMap(): Map<K, V> = HashMap<K, V>(collectionSizeOrNull() ?: 16).apply { putAll(this@toHashMap) } 

您可以使用类似于toMap函数的逻辑来选择最佳的初始地图大小,或者不要设置它并相信默认的增长实现。

Kotlin的构建很容易扩展。 如果一切都放到stdlib中,那么受限制的设备(如Android)上的用户就会抱怨它太大了,而且大多数人所要求的东西都是小问题,只是将几行代码放到自定义库中。

这不是对您的原始问题的答案,而是您的使用案例的替代解决方案。

在这里,你试图过滤HashMap<Int, Int>并将其分配回它从中获取的映射:

matchesInClass [cl] = matches.filterKeys {it!in banned} //错误:不是一个HashMap

如果你没有要求保持matches HashMap不变,你可以通过调用它的keys可变集removeAll函数就地过滤它:

 val matchesInClass: HashMap<MessageClass, HashMap<Int, Int>> //... for (matches in matchesInClass.values) { matches.keys.removeAll { it in banned } // notice the inverted condition } 

这比创建过滤副本更有效率。

另一种方法是使用Map.filterTo提供一个所需类型的空映射:

 for (entry in matchesInClass) { entry.setValue(entry.value.filterTo(HashMap()) { it !in banned }) } 

如何过滤它像这样:

val filtered = matchesInClass.mapValues { it.value.filterKeys { it !in banned } }