Kotlin:使用自定义setter时没有lateinit的解决方法?

在我的活动中,我有一个应该是不可空的字段,并有一个自定义的setter。 我想在我的onCreate方法初始化字段,所以我添加了lateinit到我的variables声明。 但是,显然你不能这样做(目前): https : //discuss.kotlinlang.org/t/lateinit-modifier-is-not-allowed-on-custom-setter/1999 。

这些是我可以看到的解决方法:

  • 用Java的方式来做。 使该字段可以为空并使用null初始化它。 我不想这样做。
  • 使用types的“默认实例”初始化该字段。 这就是我目前所做的。 但是对于某些types来说这太贵了。

有人可以推荐一个更好的方法(这不涉及删除自定义设置)?

将其替换为由可为空的属性支持的属性:

  var _tmp: String? = null var tmp: String get() = _tmp!! set(value) {_tmp=value; println("tmp set to $value")} 

或者这样,如果你想要它与lateinit语义一致:

 var _tmp: String? = null var tmp: String get() = _tmp ?: throw UninitializedPropertyAccessException("\"tmp\" was queried before being initialized") set(value) {_tmp=value; println("tmp set to $value")} 

这可以通过使用支持属性 (按照Pavlus的回答)来实现。 不过,我更喜欢把它包装在一个委托中,以避免暴露在属性的上下文之外:

 open class LateInit : ReadWriteProperty { protected lateinit var field: T final override fun getValue(thisRef: Any?, property: KProperty<*>) = get() final override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) = set(value) open fun get() = field open fun set(value: T) { field = value } } 

这提供了可以用自定义实现覆盖的标准getter和setter:

 var upperCaseString by object : LateInit() { override fun set(value: String) { field = value.toUpperCase() } } 

但是,由于这个实现需要扩展委托,genericstypes不能从属性types推断出来。 这可以通过将自定义getter和setter作为参数来克服:

 class LateInit(private val getter: FieldHolder.() -> T = { field }, private val setter: FieldHolder.(T) -> Unit = { field = it }) : ReadWriteProperty { private val fieldHolder = FieldHolder() override fun getValue(thisRef: Any?, property: KProperty<*>) = fieldHolder.getter() override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) = fieldHolder.setter(value) class FieldHolder { lateinit var field: T } } 

然后可以这样使用:

 private var upperCaseString: String by LateInit(setter = { field = it.toUpperCase() })