具有非空值的Kotlin Map

时间:2017-03-09 21:28:36

标签: collections kotlin

假设我有一张地图用于将扑克牌的字母翻译为整数

 val rank = mapOf("J" to 11, "Q" to 12, "K" to 13, "A" to 14)

使用地图时,即使地图和配对是不可变的,我也总是必须进行空安全检查:

val difference = rank["Q"]!! - rank["K"]!!

我猜这是因为泛型类型有Any吗?超类型。当Map和Pair都是不可变的时,为什么不能在编译时解决这个问题?

4 个答案:

答案 0 :(得分:11)

它不是关于Map的实现(基于Kotlin或Java)。您正在使用Map,而地图可能没有键,因此[]运算符返回可空类型。

答案 1 :(得分:7)

mapOf()提供的Map不能保证键的存在 - 特别是考虑到Map的Java实现,这是一种预期的东西。

虽然我个人可能更喜欢坚持使用空安全呼叫和elvis运营商,但听起来你更喜欢在呼叫站点使用更干净的代码(特别是考虑到你知道这些密钥存在且具有相关联的非空值)。考虑一下:

class NonNullMap<K, V>(private val map: Map<K, V>) : Map<K, V> by map {
    override operator fun get(key: K): V {
        return map[key]!! // Force an NPE if the key doesn't exist
    }
}

通过委托map的实现,但是重写get方法,我们可以保证返回值是非null的。这意味着您不再需要担心!!,?。或?:用于您的用例。

一些简单的测试代码表明这是真的:

fun main(args: Array<String>) { 
    val rank = nonNullMapOf("J" to 11, "Q" to 12, "K" to 13, "A" to 14)
    val jackValue: Int = rank["J"] // Works as expected
    println(jackValue)
    val paladinValue: Int = rank["P"] // Throws an NPE if it's not found, but chained calls are considered "safe"
    println(jackValue)
}

// Provides the same interface for creating a NonNullMap as mapOf() does for Map
fun <K, V> nonNullMapOf(vararg pairs: Pair<K, V>) = NonNullMap(mapOf<K, V>(*pairs))

答案 2 :(得分:0)

还有另一种获取not null value from map的方法:

fun <K, V> Map<K, V>.getValue(key: K): V

NoSuchElementException -当地图不包含指定键的值并且没有为该地图提供隐式默认值时。

但是 get == map [] returns nullable的运算符。

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

答案 3 :(得分:0)

简短的答案是,直到Kotlin改变,您才能实现。正如其他人指出的那样,这与可变性无关,而是Java的Map接受 null 作为有效值这一事实。目前,Kotlin的*Map类具有与Java的*Map类完全相同的实现。

如果您仍然想实现非空值映射,则需要实现自己的例如扩展Map或环绕

更具体地说,mapOf在后​​台为我们提供了Kotlin的LinkedHashMap,它不是一个不同的类,而只是Java的LinkedHashMap的 typealias

Maps.kt

public fun <K, V> mapOf(vararg pairs: Pair<K, V>): Map<K, V> =
    if (pairs.size > 0) pairs.toMap(LinkedHashMap(mapCapacity(pairs.size))) else emptyMap()

TypeAliases.kt

@SinceKotlin("1.1") public actual typealias LinkedHashMap<K, V> = java.util.LinkedHashMap<K, V>

您可以尝试使用map.getValue(key)而不是map.get(key),但我个人认为这不干净且令人困惑。

丹·露(Dan Lew)here的其他人对您有用吗?

我的Kotlin版本是1.3.72-release-IJ2020.1-3