如何使用默认包装器?

Max*_*kov 13 kotlin

我想使用MutableMap 默认值:

val myMap = mutableMapOf<String, Set<String>>().withDefault { mutableSetOf() }
Run Code Online (Sandbox Code Playgroud)

但我不能使用getOrImplicitDefault方法,因为withDefault返回MutableMap<String, Set<String>>类型.而且,我无法转换为MutableMapWithDefault接口,因为这是一个私有接口.

我无法使用get方法,因为它返回一个可空类型.没关系,因为这是MutableMap接口上的一个方法(而且它不会调用call defaultValuefor return取默认值).

好像这个功能在Kotlin中没有正确实现,或者我使用它错了.那么,我该如何withDefault正确使用包装?

Ily*_*lya 7

从Kotlin 1.0开始,返回的包装器withDefault仅可用于属性委派用例.

val map = mutableMapOf<String, Set<String>>().withDefault { mutableSetOf() }

var property: Set<String> by map // returns empty set by default
Run Code Online (Sandbox Code Playgroud)


ssc*_*rth 5

看起来在Kotlin 1.1中,如果你使用getValue()函数而不是get()函数,这实际上是有效的.

  • 看起来像是返回默认值,但没有放入地图......相当无用. (3认同)

小智 5

我一直在寻找一种从 MutableMap 返回默认值的方法,但同时也存储它以供将来检索。仅.withDefault返回默认值,但不存储它。每次我需要检索.getOrPut值时都调用看起来不是一个好主意。我想出了这样的东西:

val myMap = with(mutableMapOf<String, Set<String>>()) {
    withDefault { key -> getOrPut(key, { mutableSetOf<String>() }) }
}
Run Code Online (Sandbox Code Playgroud)

这会在支持MutableMap对象的包装器getOrPut内调用,该对象将缺少的键值对放入映射中并返回它。withDefault

要封装行为,您可以创建委托属性提供程序。

/** Wraps a [MutableMap]. Will generate a [defaultValue] if none exists, and set it into the map. */
fun <K, V> mapWithPutDefault(defaultValue: (key: K) -> V): ReadWriteProperty<Any?, MutableMap<K, V>> =
  object : ReadWriteProperty<Any?, MutableMap<K, V>> {

    private var map: MutableMap<K, V> = with(mutableMapOf<K, V>()) {
      withDefault { key -> getOrPut(key) { defaultValue(key) } }
    }

    override fun getValue(thisRef: Any?, property: KProperty<*>): MutableMap<K, V> = map

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: MutableMap<K, V>) {
      this.map = value
    }
  }

fun main() {
    val myMap: MutableMap<String, String> by mapWithPutDefault { "some default value for $it" }
    println("map is empty: $myMap")
    // map is empty: {}
    val someValue = myMap.getValue("my-key")
    println("map returns a default value: $someValue")
    // map returns a default value: some default value for my-key
    println("map now has a value: $myMap")
    // map now has a value: {my-key=some default value for my-key}
}
Run Code Online (Sandbox Code Playgroud)