在 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又是10c.yv*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 反射 类,并且会花费大量时间。