簡體   English   中英

為什么“Map”類的“get”方法可以在沒有編譯錯誤的情況下發送不相關的鍵?

[英]Why does 'get' method of class 'Map' enable sending a not relevant key without a compilation error?

我只是在我的程序中有一個錯誤,但我根本不明白該程序是如何編譯的!

我有以下變量:

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 類的原型,該方法聲明如下:

公共內聯運算符 fun <@kotlin.internal.OnlyInputTypes K, V> Map<out K, V>.get(key: K): V?

正如我們所看到的,它可以獲取 K 並且它是子類型,但是作為 CompetitionObj 類的 instacne 的競爭項並沒有繼承Long類。 那么為什么編譯器沒有阻止這個錯誤呢? 我解決了這個問題,但我很清楚什么沒有阻止代碼被編譯?

Map接口有兩種get方法。

一種是直接在接口主體中定義的:

Map<K, V> { fun get(key: K): V? }

另一個(您在問題中引用) - 作為擴展函數:

fun <K, V> Map<out K, V>.get(key: K): V?

調用時的重載解析取決於您是否明確指定泛型參數,以及映射K泛型參數類型與傳遞的key參數類型之間的關系:

  1. 如果您指定顯式泛型參數,則將調用第二個版本(如果您編寫了.get()<Long, MutableList<AllScoresGameObj>.(competitionItem) ,盡管.get()<CompetitionObj, MutableList<AllScoresGameObj>.(competitionItem) ) 會起作用,因為在這個get重載中有不安全的轉換)。
  2. 如果省略顯式泛型參數,則作為key傳遞:
    1. K類型(或其子類型)的實例 - 第一個重載將被調用
    2. 其他任何東西 - 第二個重載(因為第一個重載不會編譯)。 在這種情況下,Kotlin 將嘗試推斷省略的泛型參數,因此原始地圖可以表示為Map<out inferredK, V>並且inferredK類型參數是傳遞的key參數的超類型。 最終,它會得到inferredK = Any 事實上Any是所有事物的超類型,對任何K執行val x: Map<out Any, V> = mapOf<K, V>()是完全合法的。 實際上編譯器意識到這是一個微不足道的解決方案並發出編譯警告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 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. (我相信在你的情況下,這個警告也應該如此)。 為什么這在運行時仍然有效? 因為類型擦除

那么,為什么將這個重載版本添加到 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) 

為什么有兩個get方法?

  1. Kotlin 想要繼承Java 類型系統。
val x: kotlin.collections.List<String>= java.util.ArrayList<>()
  1. Kotlin 類型系統是不同的。 差異之一是聲明站點差異

擁有

open class A
class B

在 Java 中是非法的

List<A> x = new ArrayList<B>();

但在 Kotlin 中絕對正常

val x: List<A> = ArrayList<B>()

至於我期望的Map示例

錯誤:類型推斷失敗。 類型參數 K 的值應在輸入類型(參數類型、接收器類型或預期類型)中提及。 嘗試明確指定它

自 Kotlin 1.0.0 起類型推斷被破壞時

如果真的有問題,很高興看到您正在使用的代碼粘貼和 kotlin 編譯器版本。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM