Kotlin非可为空的地图允许删除null

时间:2019-12-18 15:07:53

标签: kotlin hashmap nullable

为什么可以在没有错误的情况下编译和执行此代码?

val map = HashMap<Int, Long>()
val key :Int? = null
map.remove(key)

在MutableMap中的 remove 中声明为仅接受不可为空的键,因此它甚至不应该编译。是Kotlin类型推断错误还是我错过了什么?

public fun remove(key: K): V?

4 个答案:

答案 0 :(得分:4)

您的代码非常好,因为remove()允许使用可为空的参数-您的地图内容定义没有任何意义。调用remove()时,它将尝试在映射中找到匹配的请求键,因为它不存在(这与为什么不存在完全无关紧要-密钥不存在是合理的情况),将不会发生任何事情。尝试将此类密钥放入到您的地图中时,编译器会抱怨的地方。然后地图定义开始,并且因为已知不允许使用可为空的键,所以这样的代码甚至无法编译,因为这显然是错误的代码。

答案 1 :(得分:1)

Kotlin可以警告或拒绝编译(会很好),但暂时不会。

之所以不如乍看起来那样糟糕,是因为您不能将putInt?变成MutableMap<Int, Long>,因为

val map = HashMap<Int, Long>()
val key :Int? = null
map.put(key, 1) // <--- WON'T COMPILE [Type mismatch: inferred type was Int? but Int was expected]
map.remove(key)

尽管如此,我认为您想知道正在编译的方法是正确的。

答案 2 :(得分:1)

在这种情况下,map.remove(key)不会拨打电话

public fun remove(key: K): V?

它调用扩展remove函数:

public inline fun <@OnlyInputTypes K, V> MutableMap<out K, V>.remove(key: K): V? =
    @Suppress("UNCHECKED_CAST") (this as MutableMap<K, V>).remove(key)

该功能文档说可以克服remove的类型安全限制,该限制要求传递类型为K的密钥。


它允许克服类型安全性限制,因为要删除的条目的键不必与传递给remove(key)的对象的类型相同;方法的规范仅要求它们相等。这是基于equals()方法如何将Any用作参数,而不仅仅是与对象相同的类型。

尽管通常会定义许多类,equals()使其对象只能等于其自身类的对象,但这在许多地方并非如此。例如,List.equals()的规范规定两个List对象都是相同的,即使它们都是List并具有相同的内容,即使它们是List的不同实现。因此,例如,根据方法的规范,可能有一个MutableMap<ArrayList<Something>, Something>并以remove(key)作为参数调用LinkedList,并且它应该检索密钥为具有相同内容的列表。如果扩展名remove(key)不存在,这将是不可能的。 [1]

答案 3 :(得分:0)

最终提出此问题有助于找到another个带有解释的问题。简而言之,实际上发生的是调用具有自己类型推断的扩展函数。