Kotlin Получатель и установщик MutableMap не работают должным образом - PullRequest
0 голосов
/ 09 апреля 2020

В классе у меня есть MutableMap, который я хочу объявить геттером и сеттером, например:

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"]

Я понимаю, что выполнение идет дважды к получателю, и ни одному к установщику.

Что я делаю не так?

Ответы [ 3 ]

1 голос
/ 09 апреля 2020

Это происходит потому, что 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()
1 голос
/ 10 апреля 2020

ОК, я думаю, я понимаю, что вы пытаетесь сделать. Вы хотите, чтобы какой-то побочный эффект происходил, когда значение добавлялось или извлекалось из MutableMap, верно?

Получатель и установщик свойства не имеют к этому никакого отношения. Они являются getter и setter для свойства, ссылкой на MutableMap. Они не являются получателем и установщиком значений в пределах самой карты.

Для этого можно использовать две разные стратегии:

1) Создайте собственную карту класс, который имеет побочные эффекты. Самый простой способ сделать это - создать подкласс существующей реализации 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) Напишите свои собственные средства доступа, которые передают вызовы средствам доступа к карте, и добавьте туда свои побочные эффекты. Это заставит вас вызывать эти указанные c функции, а не обращаться к карте напрямую из-за пределов класса, поэтому вы, вероятно, захотите сделать свойство карты protected или private.

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]
    }
}
1 голос
/ 09 апреля 2020

Я ответил на аналогичный вопрос с List вместо MutableMap пары дней go см. здесь

Вот версия с 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") }
)
...