[英]How to implement a map of lazy values in Kotlin
I have a bunch of lookup tables indexed by key
that I would like instantiate lazily (ie the tables are expensive to compute and I only expect some of them to be used on any given execution of the code).我有一堆key
索引的查找表,我想懒惰地实例化它们(即这些表的计算成本很高,我只希望它们中的一些用于任何给定的代码执行)。
private var myLazyMap: Map<KeyClass, TableClass> by lazy { ...}
Doesn't work as that makes the map object itself lazy, which isn't right.不起作用,因为这会使 map object 本身变得懒惰,这是不对的。 I think I may need to write a custom delegate, but I still can't see how to embed that into the map object.我想我可能需要编写一个自定义委托,但我仍然看不到如何将其嵌入到 map object 中。
I could wrap TableClass
with something like我可以用类似的东西包装TableClass
class LazyTable(val param: TableClassParameter) {
private var table: TableClass by lazy { TableClass(param) }
fun wrappedTableFun(): ResultClass {
return table.tableFun()
}
}
But this does mean the class is wrong and it feels like a hack.但这确实意味着 class 是错误的,感觉就像是黑客攻击。 Can this be done in a neater way?这可以以更整洁的方式完成吗?
A partial implementation could be something like this:部分实现可能是这样的:
class LazyMap<K, V>(val lazyVals: Map<K, () -> V>, val cache: MutableMap<K, V> = mutableMapOf()) : Map<K, V> by cache {
companion object {
fun <K, V> lazyMapOf(vararg entries: Pair<K, () -> V>): LazyMap<K, V> = LazyMap(mapOf(*entries))
}
override fun get(key: K): V? = cache[key] ?: lazyVals[key]?.let { cache[key] = it(); cache[key] }
}
fun main() {
val lazyMap = lazyMapOf(
1 to { println("computing one"); "one" },
2 to { println("computing two"); "two" }
)
println("get 2")
println(lazyMap[2])
println("get 1")
println(lazyMap[1])
println("get 0")
println(lazyMap[0])
println("get 2 again")
println(lazyMap[2])
}
An we can observe the lazyness in the output:我们可以观察到 output 中的惰性:
get 2
computing two
two
get 1
computing one
one
get 0
null
get 2 again
two
It could be implemented in multiple ways, depending on your needs.它可以通过多种方式实现,具体取决于您的需要。 Probably the easiest is to use a map of lazy values directly:可能最简单的方法是直接使用惰性值的 map:
val map = mutableMapOf<KeyClass, Lazy<TableClass>>()
map[myKey1] = lazy { createTable1() }
map[myKey2] = lazy { createTable2() }
val table = map[myKey1]?.value
If we want to not expose Lazy
to the users of the map, we need to create our own LazyMap
.如果我们不想将Lazy
暴露给 map 的用户,我们需要创建自己的LazyMap
。 One way is to use a map similar to above and just hide Lazy
from the user:一种方法是使用与上述类似的 map 并仅对用户隐藏Lazy
:
class LazyMap<K, V>(
private val map: Map<K, Lazy<V>>
) {
operator fun get(key: K): V? = map[key]?.value
}
Another solution is to use a function that creates values when needed:另一种解决方案是使用 function 在需要时创建值:
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) }
}
We can also use a separate compute
function per each key, as in the answer by @tibtof.我们还可以为每个键使用单独的compute
function,如@tibtof 的回答所示。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.