Kotlin: ¿solución alternativa para no lateinit cuando se usa setter personalizado?

En mi actividad tengo un campo que no debe contener nulos y tiene un setter personalizado. Quiero inicializar el campo en mi método onCreate , así que agregué lateinit a mi statement de variables. Pero, al parecer, no puede hacer eso (por el momento): https://discuss.kotlinlang.org/t/lateinit-modifier-is-not-allowed-on-custom-setter/1999 .

Estas son las soluciones alternativas que puedo ver:

  • Hazlo de la manera Java. Haga que el campo sea nulo e inícielo con nulo. No quiero hacer eso.
  • Inicialice el campo con una "instancia pnetworkingeterminada" del tipo. Eso es lo que hago actualmente. Pero eso sería demasiado caro para algunos types.

¿Alguien puede recomendar una mejor manera (que no implique eliminar el setter personalizado)?

Reemplácelo con una propiedad respaldada por una propiedad anulable:

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

o de esta manera, si quieres que sea consistente con la semántica 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")} 

Esto se puede lograr utilizando una propiedad de respaldo (según la respuesta de Pavlus); sin embargo, prefiero envolverlo dentro de un delegado para evitar exponerlo fuera del context de la propiedad:

 open class LateInit<T: Any> : ReadWriteProperty<Any?, T> { 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 } } 

Esto proporciona getters y setters estándar que pueden anularse con una implementación personalizada:

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

Sin embargo, dado que esta implementación requiere extender el delegado, el tipo genérico no se puede deducir del tipo de propiedad. Esto puede superarse tomando los parameters get y setter personalizados como parameters:

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

Que luego se puede usar así:

 private var upperCaseString: String by LateInit(setter = { field = it.toUpperCase() }) 
  • Usar el recurso en kotlin func - no funciona con el flask de grasa (un flask)
  • Cómo deserializar las classs de datos henetworkingados de Kotlin con Gson
  • Complemento de estudio Android con id: 'kotlin-android-extensions'
  • ¿En qué situación val / var es necesaria en el parámetro constructor de Kotlin?
  • Transacciones de Jooq: las conexiones no se liberan al set, si se lanza una exception en la transacción
  • Cómo recuperar datos de una tabla personalizada en Corda
  • @Param no funciona en Spring Data JPA
  • Kotlin: ¿Por qué el más / less unario no puede inferir el tipo genérico de la asignación?
  • Android Espresso IntentsMatcher funciona en un dispositivo nuevo pero no antiguo
  • ¿Cómo encontrar qué elemento no comparó las matrices en Kotlin?
  • Cómo colocar el dialog en la parte inferior