为什么可以在没有错误的情况下编译和执行此代码?
val map = HashMap<Int, Long>()
val key :Int? = null
map.remove(key)
在MutableMap中的 remove 中声明为仅接受不可为空的键,因此它甚至不应该编译。是Kotlin类型推断错误还是我错过了什么?
public fun remove(key: K): V?
答案 0 :(得分:4)
您的代码非常好,因为remove()
允许使用可为空的参数-您的地图内容定义没有任何意义。调用remove()
时,它将尝试在映射中找到匹配的请求键,因为它不存在(这与为什么不存在完全无关紧要-密钥不存在是合理的情况),将不会发生任何事情。尝试将此类密钥放入到您的地图中时,编译器会抱怨的地方。然后地图定义开始,并且因为已知不允许使用可为空的键,所以这样的代码甚至无法编译,因为这显然是错误的代码。
答案 1 :(得分:1)
Kotlin可以警告或拒绝编译(会很好),但暂时不会。
之所以不如乍看起来那样糟糕,是因为您不能将put
和Int?
变成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个带有解释的问题。简而言之,实际上发生的是调用具有自己类型推断的扩展函数。