假设我有一张地图用于将扑克牌的字母翻译为整数
val rank = mapOf("J" to 11, "Q" to 12, "K" to 13, "A" to 14)
使用地图时,即使地图和配对是不可变的,我也总是必须进行空安全检查:
val difference = rank["Q"]!! - rank["K"]!!
我猜这是因为泛型类型有Any吗?超类型。当Map和Pair都是不可变的时,为什么不能在编译时解决这个问题?
答案 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