我只是在我的程序中有一个错误,但我根本不明白程序是如何编译的!
我有以下变量:
gamesPerCountriesMap: MutableMap<Long, MutableMap<Long, MutableList<AllScoresGameObj>>>?
我有以下代码行:var gamesList = gamesPerCountriesMap?.get(countryItem.id)?.get(competitionItem)
正确的行应该是:var gamesList = gamesPerCountriesMap?.get(countryItem.id)?.get(competitionItem.id)
我查看了 Map 类的原型(prototype),方法声明如下:public inline operator fun <@kotlin.internal.OnlyInputTypes K, V> Map<out K, V>.get(key: K): V?
正如我们所看到的,它可以获得 K 和它的子类型,但是 CompetitionItem 是 CompetitionObj 类的实例,它没有继承 Long 类。
那么为什么编译器没有阻止这个错误呢?我解决了这个问题,但我很清楚什么没有阻止代码被编译?
最佳答案
有两个get
Map
的方法界面。
One直接在接口(interface)体中定义:
Map<K, V> { fun get(key: K): V? }
Another (你在你的问题中引用) - 作为一个扩展函数:fun <K, V> Map<out K, V>.get(key: K): V?
调用的重载决议取决于您是否明确指定泛型参数,以及映射类型 K
之间的关系。泛型参数和传递的类型key
争论:.get()<Long, MutableList<AllScoresGameObj>.(competitionItem)
,它不会在你的情况下编译,尽管 .get()<CompetitionObj, MutableList<AllScoresGameObj>.(competitionItem)
)会工作,因为在这个 get
里面有不安全的类型转换。重载)。 key
传递:K
的一个实例类型(或其子类型) - 第一个重载将被称为 Map<out inferredK, V>
和 inferredK
type 参数是传递的 key
的父类(super class)型争论。最终,它会提出 inferredK
= Any
.确实 Any
是所有事物的父类(super class)型,这样做是完全合法的 val x: Map<out Any, V> = mapOf<K, V>()
对于任何 K
.实际上编译器意识到这是一个简单的解决方案并发出编译警告Type inference failed. The value of the type parameter K should be mentioned in input types (argument types, receiver type or expected type). Try to specify it explicitly.
(我相信在你的情况下,这个警告也应该如此)。为什么这在运行时仍然有效?因为type erasure . 那么,为什么将这个重载版本添加到 stdlib 中呢?
不确定,也许对于某些法律案件,例如:
val k : Base = Derived()
val v = mapOf<Derived, String>().get(k) // will call overloaded variant; will infer K as Base
如果没有这个重载,您将不得不手动回退:val v = mapOf<Derived, String>().get(k as Derived)
关于dictionary - 为什么类 'get' 的 'Map' 方法允许发送不相关的 key 而没有编译错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64936150/