Kotlin MutableMap getter 和 setter 未按预期工作

Kotlin MutableMap getter and setter not working as expected

在 class 中,我有一个 MutableMap,我想声明一个 getter 和一个 setter,像这样:

open class StringList() {
    private val list= mutableListOf<String>()
    var values: MutableMap<String, String>
        get() {
            println("get member")        // this is printed.. twice
            return mutableMapOf<String, String>()
        }
        set(value) {
            println("set member")        // this is not printed
        }
     fun add(s: String, aObject: Any? = null): Int {
        list.add(s)
        return list.count() - 1
    }
}

但是当我 运行 代码时,像这样:

var sl = StringList()
sl.add("user=amo")
sl.values["user"] = "other"
val r = sl.values["user"]

我意识到 getter 执行了两次,setter 执行了两次 none。

我做错了什么?

几天前我用 List 而不是 MutableMap 回答了类似的问题,请参阅 here

这是 MutableMap

的版本
class MMap<T, U>(
        private val map: MutableMap<T, U> = mutableMapOf(),
        private val getter: ((T) -> Unit)? = null,
        private val setter: ((U) -> Unit)? = null
) : MutableMap<T, U> by map {

    override fun put(key: T, value: U): U? = 
        map.put(key, value).also { setter?.invoke(value) }

    override fun get(key: T): U? = 
         map[key].also { getter?.invoke(key) }
}

用法:

var values = MMap<String, String>(
    getter = { println("get member $it") },
    setter = { println("set member $it") }
)

发生这种情况是因为变量的 setter 在其 content 发生变化时不会被调用,但只有在存在赋值时才会被调用,而在您的情况下,您从未赋值过它。

var sl = StringList()
// Doesn't invoke the setter.
sl.add("user=amo")
// .values invokes the getter.
sl.values["user"] = "other"
// .values invokes the getter again.
val r = sl.values["user"]
// Invokes the setter since you made an assignment (this line is just an example on how to invoke the setter).
sl.values = mutableMapOf()

好的,我想我明白你想做什么。您希望在从 MutableMap 添加或检索值时发生一些副作用,对吗?

getter 和 属性 的 setter 与此无关。它们是 属性 的 getter 和 setter,对 MutableMap 的引用。它们不是地图本身中值的getter和setter。

您可以使用两种不同的策略来执行此操作:

1) 创建您自己的有副作用的地图 class。最简单的方法是通过 subclassing 一个现有的 MutableMap 实现,比如 HashMap。

open class StringList() {
    private val list = mutableListOf<String>()
    val values = object: HashMap<String, String>(){
        override fun get(key: String): String? {
            println("Retrieved map value for key $key") // Side effect here
            return super.get(key)
        }

        override fun put(key: String, value: String): String? {
            println("Put key value pair $key / $value") // Side effect here
            return super.put(key, value)
        }
    }

    //...
}

2) 编写您自己的访问器,将调用传递给地图访问器并将您的副作用放在那里。这将迫使您调用这些特定函数,而不是直接从 class 外部访问地图,因此您可能希望将地图设为 属性 protectedprivate.

open class StringList() {
    private val list = mutableListOf<String>()
    private val values = mutableMapOf<String, String>()

    //...

    fun putMapValue(key: String, value: String) {
        println("Put key value pair $key / $value") // Side effect here
        values[key] = value
    }

    fun getMapValue(key: String): String? {
        println("Retrieved map value for key $key") // Side effect here
        return values[key]
    }
}