在 Kotlin 中重新初始化对象属性
Re-initialize object properties in Kotlin
我经常有一个 class 具有在实例化时初始化的属性,例如
class C {
var x = 10
var y = v * 2 // v is some variable
}
val c = C()
然后c
的属性改变了,稍后我需要重新初始化属性(这样c.x
又是10
,c.y
是v*2
,其中 v
的值可能已更改)。
我目前的方法是用虚拟值初始化属性(或者使用 lateinit
和类型注释),并在额外的函数 ini
中分配所需的值,比如
class C {
var x = 0
var y = 0
init {
ini()
}
fun ini() {
x = 10
y = v * 2
}
}
然后调用c.ini()
重新初始化
是否有更好(更简洁)的方法来避免虚拟值?
请注意,在 JavaScript 中我可以简单地写
class C {
constructor() {
this.ini()
}
ini() {
this.x = 10
this.y = v * 2
}
}
你现在所做的一切都很好。我不会改变它。
如果您想避免 0
的占位符值,或者如果 属性 的类型没有有意义的占位符值,您可以将初始值存储在私有 lambda 中:
class C {
private val xInit = { 10 }
private val yInit = { v * 2 }
var x = xInit()
var y = yInit()
fun reset() {
x = xInit()
y = yInit()
}
}
如果你真的想要减少样板文件,我只能想到这个依赖于反射的相当笨拙和缓慢的解决方案。如果实例不需要经常重置,那么这个 可能 可用,并且你有很多这样的 类 具有可重置的属性,而你只是讨厌编写样板文件 reset
方法。
class Resettable<T>(val supplier: () -> T) {
var wrapped = supplier()
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
return wrapped
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
wrapped = value
}
fun reset() {
wrapped = supplier()
}
}
fun <T: Any> T.reset() {
// look for properties delegated with Resettable
this::class.memberProperties.mapNotNull {
it.isAccessible = true
(it as KProperty1<T, *>).getDelegate(this)
}.filterIsInstance<Resettable<*>>().forEach {
it.reset()
}
}
现在您只需要做:
var v = 10
class C {
var x by Resettable { 10 }
var y by Resettable { v * 2 }
}
fun main() {
val x = C()
println(x.y) // 20
v = 20
x.reset()
println(x.y) // 40
v = 40
x.reset()
println(x.y) // 80
}
请注意,第一个 reset
调用会加载所有 kotlin 反射 类,并且会花费大量时间。
我经常有一个 class 具有在实例化时初始化的属性,例如
class C {
var x = 10
var y = v * 2 // v is some variable
}
val c = C()
然后c
的属性改变了,稍后我需要重新初始化属性(这样c.x
又是10
,c.y
是v*2
,其中 v
的值可能已更改)。
我目前的方法是用虚拟值初始化属性(或者使用 lateinit
和类型注释),并在额外的函数 ini
中分配所需的值,比如
class C {
var x = 0
var y = 0
init {
ini()
}
fun ini() {
x = 10
y = v * 2
}
}
然后调用c.ini()
重新初始化
是否有更好(更简洁)的方法来避免虚拟值?
请注意,在 JavaScript 中我可以简单地写
class C {
constructor() {
this.ini()
}
ini() {
this.x = 10
this.y = v * 2
}
}
你现在所做的一切都很好。我不会改变它。
如果您想避免 0
的占位符值,或者如果 属性 的类型没有有意义的占位符值,您可以将初始值存储在私有 lambda 中:
class C {
private val xInit = { 10 }
private val yInit = { v * 2 }
var x = xInit()
var y = yInit()
fun reset() {
x = xInit()
y = yInit()
}
}
如果你真的想要减少样板文件,我只能想到这个依赖于反射的相当笨拙和缓慢的解决方案。如果实例不需要经常重置,那么这个 可能 可用,并且你有很多这样的 类 具有可重置的属性,而你只是讨厌编写样板文件 reset
方法。
class Resettable<T>(val supplier: () -> T) {
var wrapped = supplier()
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
return wrapped
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
wrapped = value
}
fun reset() {
wrapped = supplier()
}
}
fun <T: Any> T.reset() {
// look for properties delegated with Resettable
this::class.memberProperties.mapNotNull {
it.isAccessible = true
(it as KProperty1<T, *>).getDelegate(this)
}.filterIsInstance<Resettable<*>>().forEach {
it.reset()
}
}
现在您只需要做:
var v = 10
class C {
var x by Resettable { 10 }
var y by Resettable { v * 2 }
}
fun main() {
val x = C()
println(x.y) // 20
v = 20
x.reset()
println(x.y) // 40
v = 40
x.reset()
println(x.y) // 80
}
请注意,第一个 reset
调用会加载所有 kotlin 反射 类,并且会花费大量时间。