如何在 Kotlin 中实现惰性值映射

Oli*_*ews 1 kotlin

我有一堆查找表,key我想延迟实例化这些查找表(即这些表的计算成本很高,我只希望其中的一些表在任何给定的代码执行中使用)。

private var myLazyMap: Map<KeyClass, TableClass> by lazy { ...}
Run Code Online (Sandbox Code Playgroud)

不起作用,因为这会使地图对象本身变得懒惰,这是不对的。我想我可能需要编写一个自定义委托,但我仍然不知道如何将其嵌入到地图对象中。

可以TableClass用类似的东西包裹

class LazyTable(val param: TableClassParameter) {
   private var table: TableClass by lazy { TableClass(param) }

   fun wrappedTableFun(): ResultClass {
     return table.tableFun()
   }
}
Run Code Online (Sandbox Code Playgroud)

但这确实意味着该类是错误的,而且感觉就像是黑客攻击。这可以以更简洁的方式完成吗?

bro*_*oot 6

它可以根据您的需要以多种方式实施。也许最简单的方法是直接使用惰性值映射:

val map = mutableMapOf<KeyClass, Lazy<TableClass>>()

map[myKey1] = lazy { createTable1() }
map[myKey2] = lazy { createTable2() }

val table = map[myKey1]?.value
Run Code Online (Sandbox Code Playgroud)

如果我们不想暴露Lazy给地图的用户,我们需要创建自己的LazyMap. 一种方法是使用与上面类似的地图,并对Lazy用户隐藏:

class LazyMap<K, V>(
    private val map: Map<K, Lazy<V>>
) {
    operator fun get(key: K): V? = map[key]?.value
}
Run Code Online (Sandbox Code Playgroud)

另一个解决方案是使用一个在需要时创建值的函数:

class LazyMap<K, V>(
    private val compute: (K) -> V
) {
    private val map = mutableMapOf<K, V>()

    operator fun get(key: K): V? = map.getOrPut(key) { compute(key) }
}
Run Code Online (Sandbox Code Playgroud)

我们还可以为compute每个键使用单独的函数,如 @tibtof 的答案。