gpt4 book ai didi

delegates - 为什么 kotlin 不允许协变 mutablemap 成为委托(delegate)?

转载 作者:IT老高 更新时间:2023-10-28 13:43:04 25 4
gpt4 key购买 nike

我是 Kotlin 的新手。当我学习 Storing Properties in a Map .我尝试以下用法。

class User(val map: MutableMap<String, String>) {
val name: String by map
}

class User(val map: MutableMap<String, in String>) {
val name: String by map
}

class User(val map: MutableMap<String, out String>) {
val name: String by map
}

前两个都可以,最后一个失败。使用 out 修饰符,getName 的字节码如下:

  public final java.lang.String getName();
0 aload_0 [this]
1 getfield kotl.User.name$delegate : java.util.Map [11]
4 astore_1
5 aload_0 [this]
6 astore_2
7 getstatic kotl.User.$$delegatedProperties : kotlin.reflect.KProperty[] [15]
10 iconst_0
11 aaload
12 astore_3
13 aload_1
14 aload_3
15 invokeinterface kotlin.reflect.KProperty.getName() : java.lang.String [19] [nargs: 1]
20 invokestatic kotlin.collections.MapsKt.getOrImplicitDefaultNullable(java.util.Map, java.lang.Object) : java.lang.Object [25]
23 checkcast java.lang.Object [4]
26 aconst_null
27 athrow
Local variable table:
[pc: 0, pc: 28] local: this index: 0 type: kotl.User

如我们所见,它会导致NullPointerException

为什么 map 委托(delegate)上不允许逆变?

为什么 kotlin 没有给我编译错误?

最佳答案

简短回答:这不是编译器中的错误,而是operator getValue() 的签名的不幸结果。为 MutableMap 声明.

长答案: delegating properties由于标准库中的以下三个运算符函数,to maps 是可能的:

// for delegating val to read-only map
operator fun <V, V1: V> Map<in String, @Exact V>.getValue(thisRef: Any?, property: KProperty<*>): V1

// for delegating var to mutable map
operator fun <V> MutableMap<in String, in V>.getValue(thisRef: Any?, property: KProperty<*>): V

operator fun <V> MutableMap<in String, in V>.setValue(thisRef: Any?, property: KProperty<*>, value: V)

这里是 MutableMap 的使用地点差异选择接收者以便可以将某种类型的属性委托(delegate)给可以存储其父类(super class)型的映射:

class Sample(val map: MutableMap<String, Any>) {
var stringValue: String by map
var intValue: Int by map
}

不幸的是,当您尝试使用超出投影的 MutableMap<String, out String>作为 val 的委托(delegate)属性(property),因此作为 getValue 的接收者运算符(operator),这里会发生什么:

  • MutableMap<in String, in V>.getValue选择了重载,因为它具有更具体的接收器类型。
  • 由于接收者 map 有 out String类型参数投影它的实际类型参数是未知的(它可以是 MutableMap<..., String>MutableMap<..., SubTypeOfString> ),所以唯一安全的选择是假设它是 Nothing ,它是所有可能类型的子类型。
  • 这个函数的返回类型声明为V已推断为 Nothing ,并且编译器会插入一个检查,确认实际返回的值是 Nothing 类型。 ,这应该总是失败,因为不可能有 Nothing 类型的值.这个检查看起来像 throw null在字节码中。

我打开了一个问题 KT-18789看看我们可以用这个操作符函数的签名来做什么。

UPD:签名已在 Kotlin 1.2.20 中修复

同时作为一种解决方法,您可以使用 MutableMapMap ,因此 getValue 的第一个重载被选中:

class User(val map: MutableMap<String, out String>) {
val name: String by map as Map<String, String>
}

关于delegates - 为什么 kotlin 不允许协变 mutablemap 成为委托(delegate)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44665427/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com