Kotlin:有什么糖可以在局部范围内只初始化一次值,就像 C 中的静态局部一样?

问题描述 投票:0回答:1

Kotlin 中是否有任何糖可以在局部范围内仅初始化一次值,就像 C 中的静态局部变量一样?或者等效地,要在全局或类范围内拥有一个值,就像本地一样声明和使用?

我有一些 lambda 使用只需要初始化一次的数据:

enum class Type { GOOD, BAD, UGLY }

class Job(val state: Type, val foo: Foo) {}

// Given a list of Jobs, sort it in Type declaration order, then display it
fun displayJobs(jobs: List<Job>) {
   textView.text = jobs.sortedBy { it -> 
     val order = Type.entries.withIndex().associate { (i, v) -> Pair(v, i) }
     order.get(it.state)!! 
   }
}

我希望

order
位于 lambda 的范围内,因为这是它唯一使用的地方。但这意味着它会在“每次调用 lambda”时被重复计算。对于传递给 sort 的 lambda,这将是 n log n 函数调用和 Map 的副本! 我可以将其移出到函数作用域,但每次调用函数时它仍然会重新计算:

enum class Type { GOOD, BAD, UGLY } fun displayJobs(jobs: List<Job>) { val order = Type.entries.withIndex().associate { (i, v) -> Pair(v, i) } textView.text = jobs.sortedBy { it -> order.get(it.state)!! } }

我可以将 
order

移动到某个顶级范围或伴生对象,并对其进行一次计算,但现在它距离其使用地点很远。

我可以将 

order

放入枚举类中,但我必须能够声明一个伴生对象:

inline fun <reified T : Enum<T>> enumOrder() 
   = enumValues<T>().withIndex().associate { (i, v) -> Pair(v, i) }

enum class Type { GOOD, BAD, UGLY; 
   companion object {
       val order = enumOrder<Type>()
   }
}

这个“缓存”顺序到一个val中,所以它不会被重新计算,并且它的访问方式并不令人惊讶:

fun displayJobs(jobs: List<Job>) { textView.text = jobs.sortedBy { it -> Type.order.get(it.state)!! } }

所以耶!!问题解决了!

除了...

对于我不拥有的枚举,我无法添加伴随对象,可以吗?

我可以将扩展属性附加到类中:

val KClass<Type>.order get() = enumValues<Type>().withIndex().associate { (i, v) -> Pair(v, i) } textView.text = jobs.sortedBy { it -> Type::class.order.get(it.state)!! }

但是

扩展属性不会分配内存,因此每次运行 lambda 时都会调用 get():我们又回到了开始的地方!

Type.entries.sortedBy { Type::class.order.get(it)!! }

调用该函数四次。

那么,Kotlin 是否提供了类似于 C 的

static

修饰符的东西?请注意,

lazy
并没有回答这个问题,在:
fun displayJobs(jobs: List<Job>) {
   textView.text = jobs.sortedBy { it -> 
     val order by lazy { Type.entries.withIndex().associate { (i, v) -> Pair(v, i) } }
     order.get(it.state)!! 
   }
}

每次
order
调用 lambda 时都会(延迟)创建

sortedBy
,这又与要排序的元素数量成正比。
    

kotlin lambda static
1个回答
1
投票

跳过构建枚举对并直接使用序数属性怎么样?例如,

listOf(Job(UGLY, ..), Job(BAD, ..), Job(GOOD, ..)) .sortedBy { it.state.ordinal })

应该按顺序给你工作:好、坏和丑。

© www.soinside.com 2019 - 2024. All rights reserved.