寻找一种自然的 Kotlin 方法,让 startTime
仅在特定位置初始化一次。
以下简单的实现有两个问题:
- 它不是线程安全的
- 它没有表达“变量在 Item 实例的生命周期中曾经或将被分配一次”的事实
class Item {
var startTime: Instant?
fun start(){
if (startTime == null){
startTime = Instant.now()
}
// do stuff
}
}
我相信某种委托(delegate)可以适用于此。换句话说,这段代码需要类似于惰性变量的东西,但在第一次读取时没有初始化,而是仅在显式调用“touching”方法之后才会发生。也许 Wrap
调用可以给出可能的实现的想法。
class Wrap<T>(
supp: () -> T
){
private var value: T? = null
private val lock = ReentrantLock()
fun get(){
return value
}
fun touch(){
lock.lock()
try{
if (value == null){
value = supp()
} else {
throw IllegalStateExecption("Duplicate init")
}
} finally{
lock.unlock()
}
}
}
最佳答案
合并AtomicReference.compareAndSet
怎么样?与定制backing field ?
您可以使用私有(private) setter ,并确保类设置值的唯一位置是来自 start()
方法。
class Item(val value: Int) {
private val _startTime = AtomicReference(Instant.EPOCH)
var startTime: Instant?
get() = _startTime.get().takeIf { it != Instant.EPOCH }
private set(value) = check(_startTime.compareAndSet(Instant.EPOCH, value)) { "Duplicate set" }
fun start() {
startTime = Instant.now()
}
override fun toString() = "$value: $startTime"
}
fun main() = runBlocking {
val item1 = Item(1)
val item2 = Item(2)
println(Instant.now())
launch { println(item1); item1.start(); println(item1) }
launch { println(item1) }
delay(1000)
println(item2)
item2.start()
println(item2)
println(item2)
item2.start()
}
示例输出:
2021-07-14T08:20:27.546821Z
1: null
1: 2021-07-14T08:20:27.607365Z
1: 2021-07-14T08:20:27.607365Z
2: null
2: 2021-07-14T08:20:28.584114Z
2: 2021-07-14T08:20:28.584114Z
Exception in thread "main" java.lang.IllegalStateException: Duplicate set
关于kotlin - Kotlin "assign value exactly once on the first call"如何表达?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68372363/