重写子类中的kotlin运算符扩展函数



我正在尝试编写我自己的LinkedHashMap子类,该子类在更新时执行一些附加功能。这看起来像以下内容:

class MyMap(): LinkedHashMap<String, String>() {
operator fun set(key: String, value: String) {
super.put(key, value)
doSomethingWith(value)
}
}

然后,我声明一个类型为MutableMap<String, String>的变量,并为其分配一个类型MyMap的对象:

val myMap: MutableMap<String, String> = MyMap()

然而,如果我现在尝试使用我修改后的操作员方法

myMap["key"] = "value"

我写的方法没有被调用,但在kotlin中为MutableMap定义的扩展函数(kotlin/collections/Maps.kt(是。这部分我不理解,因为我的变量的声明类型是一个接口(所以静态解析该方法应该是不可能的(,而动态类型是MyMap,它定义了CCD_ 5运算符,并且没有它的扩展函数(无论哪种方式,都不能在类本身中隐藏实际实现(。如果我将变量的静态类型声明为MyMap,那么函数将按预期调用。如果我的变量的声明类型不同,为什么Kotlin会通过父类解析函数?

免责声明:我将通过重写put函数来解决这个问题,所以我的问题与其说是具体的解决方案,不如说是为这种奇怪的行为找到解释。

您的set方法在其任何超类或其实现的任何接口中都没有override,因此首先不可能通过MutableMap接口动态解析到set方法。事实上,层次结构中没有实例方法set可供您重写。set是一个扩展函数!

operator fun <K, V> MutableMap<K, V>.set(key: K, value: V)

基本上,上面的扩展函数和您编写的set是两个不相关的可调用函数。编译器只在编译时类型为MutableMap时看到前者。

当编译时类型为MyMap时,它解析为您的set,因为它总是将非扩展函数优先于扩展函数。请参阅此处了解确切的优先级。

在这种情况下,您可以实际覆盖(在一般意义上,而不是override(内置的set,只需用相同的签名重新声明您自己的扩展

operator fun <K, V> MutableMap<K, V>.set(key: K, value: V) {
...
}

这是因为包作用域中的扩展函数和显式导入的扩展函数比隐式导入的扩展函数具有更高的优先级。kotlin.collections包中的内置set是隐式导入的。

但如果你想要动态分辨率,那是行不通的。

这是因为您将变量声明为MutableMap<String, String>

只是换了这条线

val myMap: MutableMap<String, String> = MyMap()

val myMap = MyMap()

val myMap : MyMap = MyMap()

应该解决

最新更新